home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / loadavg / RCS / loadAvg.c,v < prev    next >
Encoding:
Text File  |  1988-11-14  |  73.3 KB  |  3,261 lines

  1. head     2.12;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 2.12
  10. date     88.06.23.11.46.48;  author douglis;  state Exp;
  11. branches ;
  12. next     2.11;
  13.  
  14. 2.11
  15. date     88.06.17.14.17.50;  author douglis;  state Exp;
  16. branches ;
  17. next     2.10;
  18.  
  19. 2.10
  20. date     88.05.15.20.44.42;  author douglis;  state Exp;
  21. branches ;
  22. next     2.9;
  23.  
  24. 2.9
  25. date     88.04.07.10.29.06;  author douglis;  state Exp;
  26. branches ;
  27. next     2.8;
  28.  
  29. 2.8
  30. date     88.03.17.22.42.45;  author douglis;  state Exp;
  31. branches ;
  32. next     2.7;
  33.  
  34. 2.7
  35. date     88.02.21.15.54.34;  author douglis;  state Exp;
  36. branches ;
  37. next     2.6;
  38.  
  39. 2.6
  40. date     87.12.02.12.02.46;  author douglis;  state Exp;
  41. branches ;
  42. next     2.5;
  43.  
  44. 2.5
  45. date     87.12.01.20.52.50;  author douglis;  state Exp;
  46. branches ;
  47. next     2.4;
  48.  
  49. 2.4
  50. date     87.11.20.12.40.01;  author douglis;  state Exp;
  51. branches ;
  52. next     2.3;
  53.  
  54. 2.3
  55. date     87.11.19.19.52.47;  author douglis;  state Exp;
  56. branches ;
  57. next     2.2;
  58.  
  59. 2.2
  60. date     87.03.15.21.33.15;  author douglis;  state Exp;
  61. branches ;
  62. next     2.1;
  63.  
  64. 2.1
  65. date     87.03.11.18.12.13;  author douglis;  state Exp;
  66. branches ;
  67. next     2.0;
  68.  
  69. 2.0
  70. date     87.03.11.12.39.41;  author douglis;  state Exp;
  71. branches ;
  72. next     1.8;
  73.  
  74. 1.8
  75. date     87.03.11.11.09.50;  author douglis;  state Exp;
  76. branches ;
  77. next     1.7;
  78.  
  79. 1.7
  80. date     87.03.09.12.14.30;  author douglis;  state Exp;
  81. branches ;
  82. next     1.6;
  83.  
  84. 1.6
  85. date     87.03.03.14.57.39;  author douglis;  state Exp;
  86. branches ;
  87. next     1.5;
  88.  
  89. 1.5
  90. date     87.02.23.20.13.41;  author douglis;  state Exp;
  91. branches ;
  92. next     1.4;
  93.  
  94. 1.4
  95. date     87.02.19.15.47.20;  author douglis;  state Exp;
  96. branches ;
  97. next     1.3;
  98.  
  99. 1.3
  100. date     87.02.19.15.17.17;  author douglis;  state Exp;
  101. branches ;
  102. next     1.2;
  103.  
  104. 1.2
  105. date     87.02.15.22.31.46;  author douglis;  state Exp;
  106. branches ;
  107. next     1.1;
  108.  
  109. 1.1
  110. date     87.02.15.20.53.15;  author douglis;  state Exp;
  111. branches ;
  112. next     ;
  113.  
  114.  
  115. desc
  116. @Maintain load average information on a per-host basis.  This program
  117. may be invoked as a daemon (to update global state on a regular basis)
  118. or as a stand-alone program (to return the load of the local host).
  119. @
  120.  
  121.  
  122. 2.12
  123. log
  124. @removed some old flags
  125. @
  126. text
  127. @/*
  128.  * loadAvg.c --
  129.  *
  130.  *    Maintain load average information on a per-host basis.  This program
  131.  *    may be invoked as a daemon (to update global state on a regular basis)
  132.  *    or as a stand-alone program (to return the load of the local host or
  133.  *     all hosts on the network).
  134.  *
  135.  * Copyright 1987 Regents of the University of California
  136.  * All rights reserved.
  137.  */
  138.  
  139. #ifndef lint
  140. static char rcsid[] = "$Header: loadAvg.c,v 2.11 88/06/17 14:17:50 douglis Exp $ SPRITE (Berkeley)";
  141. #endif not lint
  142.  
  143.  
  144. #include "loadAvg.h"
  145. #include "sys.h"
  146. #include "option.h"
  147. #include "rand.h"
  148. #include "string.h"
  149. #include "syslog.h"
  150. #include "host.h"
  151.  
  152. /*
  153.  * Define constants for defaults values of variables that may be assigned
  154.  * by command-line arguments.
  155.  */
  156.  
  157. /*
  158.  * Constants specific to gathering load average statistics.  (The weights may
  159.  * be modified with -D options but are not user-specifiable on the
  160.  * command line.)  The LOAD_INTERVAL is the number of seconds between sampling
  161.  * the utilization and ready queue lengths, and the WRITE_INTERVAL is the
  162.  * maximum number of seconds that may pass between updating the shared data
  163.  * file.  (The private data file is updated on each iteration.)
  164.  * For example, to write once per minute if the state of a machine doesn't
  165.  * change between idle and inUse, WRITE_INTERVAL would be (12 * LOAD_INTERVAL).
  166.  * To write every time, set it equal to LOAD_INTERVAL.  TIME_OUT is the
  167.  * default time to allow a host before assuming it's down.
  168.  */
  169.  
  170. #define LOAD_INTERVAL 5
  171. #define WRITE_INTERVAL (12 * LOAD_INTERVAL)
  172. #define TIME_OUT 180
  173.  
  174. #define WEIGHT1 (double) 0.9200444146293232     /* exp(-1/12) */
  175. #define WEIGHT2 (double) 0.9834714538216174     /* exp(-1/60) */
  176. #define WEIGHT3 (double) 0.9944598480048967     /* exp(-1/180) */
  177.  
  178. double weights[] = {WEIGHT1, WEIGHT2, WEIGHT3};
  179.  
  180.  
  181. /*
  182.  * Define arbitrary thresholds (see loadAvg.h).
  183.  *
  184.  * All load values must be below THRESHOLD_LOW to start accepting foreign
  185.  * processes, but once they are being accepted, there are different
  186.  * thresholds for each average: if any one of them is exceeded, stop
  187.  * aceepting foreign processes.
  188.  *
  189.  * INPUT_THRESHOLD is the number of seconds that a node must
  190.  * be idle for it to accept migrated processes.  (Set to a low value for
  191.  * testing.)
  192.  */
  193.  
  194.  
  195. #define THRESHOLD_LOW 0.3
  196. #define THRESHOLD_HIGH0 2.0
  197. #define THRESHOLD_HIGH1 1.0
  198. #define THRESHOLD_HIGH2 0.5
  199. #define INPUT_THRESHOLD 30
  200.  
  201. Thresholds thresholds = {
  202.     INPUT_THRESHOLD,
  203.     {THRESHOLD_LOW, THRESHOLD_LOW, THRESHOLD_LOW},
  204.     {THRESHOLD_HIGH0, THRESHOLD_HIGH1, THRESHOLD_HIGH2}
  205. };
  206.  
  207. Boolean allHosts = FALSE;
  208. Boolean getLoad = FALSE;
  209. Boolean runDaemon = FALSE;
  210. Boolean debug = FALSE;
  211. Boolean verbose = FALSE;
  212. int loadInterval = LOAD_INTERVAL;
  213. int writeInterval = WRITE_INTERVAL;
  214. int timeOut = TIME_OUT;
  215. Boolean getIdleNode = FALSE;
  216. Boolean forkChild = FALSE;
  217. Boolean zapHostInfo = FALSE;
  218.  
  219. /*
  220.  * Both of these are temporary areas to hold changes in the default values.
  221.  * If untouched by options, then they aren't used.  (LowThreshold is 
  222.  * replicated in thresholds.min[0..2].)
  223.  */
  224.  
  225. double lowThreshold = THRESHOLD_LOW;
  226. char *thresholdString = NULL;
  227.  
  228. char *myName = NULL;
  229.  
  230. Option optionArray[] = {
  231.     {OPT_TRUE, 'a', (Address)&allHosts,
  232.          "Get the load average of all nodes (DEFAULT for 'rup')."},
  233.     {OPT_TRUE, 'l', (Address)&getLoad,
  234.          "Get the load average of this node (DEFAULT for 'loadAvg')."},
  235.     {OPT_TRUE, 'i', (Address)&getIdleNode,
  236.          "Get the hostID of an idle node."},
  237.     {OPT_TRUE, 'd', (Address)&runDaemon,
  238.     "Run as a daemon and report load information to the global file."},
  239.     {OPT_TRUE, 'D', (Address)&debug, "Enable debugging information."},
  240.     {OPT_TRUE, 'v', (Address)&verbose,
  241.          "Report to stderr when no idle nodes available."},
  242.     {OPT_INT, 'I', (Address)&loadInterval,
  243.     "Interval between iterations for getting load info."},
  244.     {OPT_INT, 'w', (Address)&writeInterval,
  245.          "Maximum interval between outputting load info."},
  246.     {OPT_INT, 'W', (Address)&timeOut,
  247.          "Maximum time during which info is valid without update."},
  248.     {OPT_TRUE, 'F', (Address)&forkChild, "Fork off daemons."},
  249.     {OPT_INT, 'N', (Address)&thresholds.noInput,
  250.          "Minimum idle time to allow foreign procs."},
  251.     {OPT_FLOAT, 't', (Address)&lowThreshold,
  252.          "Maximum load average to allow foreign procs."},
  253.     {OPT_STRING, 'T', (Address)&thresholdString,
  254.          "Set of maximum thresholds before refusing migration, once allowed (as in the form '-T \"0.5 1.0 2.0\"')."},
  255.     {OPT_TRUE, 'Z', (Address)&zapHostInfo,
  256.          "Zap (remove) the information for hosts specified as remaining arguments."},
  257. };
  258. static int numOptions = sizeof(optionArray) / sizeof(Option);
  259.  
  260. typedef enum {
  261.     DOWN,
  262.     UP,
  263.     IDLE
  264. } MachineState;
  265.  
  266. /*
  267.  * Global variables.
  268.  */
  269. Time currentTime;
  270. int hostID;
  271. int archType;
  272.  
  273.  
  274. static void ListHosts();
  275. static void OutputStatus();
  276. static void ZapHostInfo();
  277. static char  *UpString();
  278.  
  279.  
  280.  
  281. /*
  282.  *----------------------------------------------------------------------
  283.  *
  284.  * Main --
  285.  *
  286.  *    The driver for the loadAvg program.  Parse options and invoke
  287.  *    subroutines as appropriate.
  288.  *
  289.  * Results:
  290.  *    None.
  291.  *
  292.  * Side effects:
  293.  *    The global var. 'hostID' is initialized.
  294.  *
  295.  *----------------------------------------------------------------------
  296.  */
  297.  
  298. int
  299. main(argc, argv)
  300.     int argc;
  301.     char *argv[];
  302. {
  303.     register ReturnStatus status = SUCCESS;
  304.     int numScanned;
  305.     int i;
  306.     int host;
  307.     Host_Info info;
  308.     
  309.  
  310.     status = Opt_Parse(&argc, argv, numOptions, optionArray);
  311.     if (status != SUCCESS) {
  312.     Stat_PrintMsg(status, "Error in Opt_Parse");
  313.     Proc_Exit(status);
  314.     }
  315.  
  316.     myName = argv[0];
  317.  
  318.     /*
  319.      * Process interrelated defaults and perform sanity checking on
  320.      * arguments.
  321.      */
  322.  
  323.     /*
  324.      * Default operation is to get the local load, using a global data file.
  325.      */
  326.  
  327.     if (! (runDaemon || getIdleNode || getLoad || zapHostInfo)) {
  328.     if (String_FindSubstring(myName, "rup") != NULL) {
  329.         getLoad = TRUE;
  330.         allHosts = TRUE;
  331.     } else {
  332.         getLoad = TRUE;
  333.     }
  334.     }
  335.  
  336.     if (lowThreshold != THRESHOLD_LOW) {
  337.     for (i = 0; i < LOAD_NUM_VALUES; i++) {
  338.         thresholds.min[i] = lowThreshold;
  339.     }
  340.     }
  341.     
  342.     if (thresholdString) {
  343.     numScanned = Io_ScanString(thresholdString, "%lf %lf %lf",
  344.                    &thresholds.max[0], &thresholds.max[1],
  345.                    &thresholds.max[2]);
  346.     if (numScanned < 3) {
  347.         Io_PrintStream(io_StdErr, "%s: Invalid thresholds '%s'.\n",
  348.                thresholdString);
  349.         Proc_Exit(FAILURE);
  350.     }
  351.     }
  352.  
  353.     if (writeInterval < loadInterval) {
  354.     writeInterval = loadInterval;
  355.     }
  356.  
  357.     if (debug && runDaemon) {
  358.     Io_PrintStream(io_StdErr, "Weights are %f, %f, %f.\n",
  359.                weights[0], weights[1], weights[2]);
  360.     }
  361.  
  362.     /*
  363.      * Initialize global variables.
  364.      */
  365.     status = Sys_GetMachineInfo(&archType, NULL, &hostID);
  366.     if (status != SUCCESS) {
  367.     syslog(LOG_ERR, "%s: Error in Sys_GetMachineInfo: %s\n", myName,
  368.            Stat_GetMsg(status));
  369.     Proc_Exit(status);
  370.     }
  371.     status = Sys_GetTimeOfDay(¤tTime, NULL, NULL);
  372.     if (status != SUCCESS) {
  373.     syslog(LOG_ERR, "%s: Error in Sys_GetTimeOfDay: %s\n", myName,
  374.            Stat_GetMsg(status));
  375.     Proc_Exit(status);
  376.     }
  377.  
  378.     if (debug) {
  379.         Io_PrintStream(io_StdErr, "My hostID is %d.\n", hostID);
  380.     }
  381.  
  382.     if (zapHostInfo) {
  383.     for (i = 1; i < argc; i++) {
  384.         ZapHostInfo(argv[i]);
  385.     }
  386.     }
  387.     if (runDaemon) {
  388.     RunDaemon();
  389.     }
  390.     if (getIdleNode) {
  391.     status = Host_GetIdleNode(&host);
  392.     if (status == SUCCESS) {
  393.         Io_Print("%d\n", host);
  394.     } else if (verbose) {
  395.         Io_PrintStream(io_StdErr, "No idle node found.\n");
  396.     }
  397.     }
  398.     if (getLoad) {
  399.     if (allHosts) {
  400.         ListHosts();
  401.     } else {
  402.         status = Host_GetInfo((int) PROC_MY_HOSTID, &info);
  403.         if (status != SUCCESS) {
  404.         Stat_PrintMsg(status, "Error in Host_GetInfo");
  405.         Proc_Exit(status);
  406.         }
  407.         OutputStatus(&info);
  408.     }
  409.     }
  410.  
  411.     Proc_Exit(status);
  412. }
  413.  
  414.  
  415. /*
  416.  *----------------------------------------------------------------------
  417.  *
  418.  * ListHosts --
  419.  *
  420.  *    Output the load average and status of all nodes.
  421.  *
  422.  * Results:
  423.  *    None.
  424.  *
  425.  * Side effects:
  426.  *    The data are is written to io_StdOut.
  427.  *
  428.  *----------------------------------------------------------------------
  429.  */
  430.  
  431. static void
  432. ListHosts()
  433. {
  434.     int numRecs;
  435.     ReturnStatus status;
  436.     register Host_Info *infoPtr;
  437.     Host_Info *infoArray;
  438.     int i;
  439.     int maxSize;
  440.  
  441.     if (debug) {
  442.     Io_PrintStream(io_StdErr, "ListHosts called.\n");
  443.      Io_Flush(io_StdErr);
  444.     }
  445.  
  446.     maxSize = MAX_NUM_HOSTS * sizeof(Host_Info);
  447.     infoArray = (Host_Info *) Mem_Alloc(maxSize);
  448.     status = Host_GetAllInfo(MAX_NUM_HOSTS, infoArray, &numRecs);
  449.     if (status != SUCCESS) {
  450.     Stat_PrintMsg(status, "Error in Host_GetAllInfo");
  451.     Proc_Exit(status);
  452.     }
  453.     if (debug && numRecs == 0) {
  454.     Io_PrintStream(io_StdErr, "No host records found.\n");
  455.      Io_Flush(io_StdErr);
  456.     return;
  457.     }
  458.     
  459.  
  460.     for (i = 0; i < numRecs; i++) {
  461.     infoPtr = &infoArray[i];
  462.     if (infoPtr->timestamp != 0) {
  463.         if (i != infoPtr->hostID) {
  464.         Io_PrintStream(io_StdErr,
  465.                    "ListHosts: mismatch between counter (%d) and value in data file (%d).\n",
  466.                    i, infoPtr->hostID);
  467.         Proc_Exit(FAILURE);
  468.         }
  469.         OutputStatus(infoPtr);
  470.     }
  471.     }
  472.     Mem_Free((Address) infoArray);
  473. }
  474.  
  475.  
  476.  
  477. /*
  478.  *----------------------------------------------------------------------
  479.  *
  480.  * OutputStatus --
  481.  *
  482.  *    Determine the status of the given host and write a "ruptime"-like
  483.  *    record to stdout.
  484.  *
  485.  * Results:
  486.  *    None.
  487.  *
  488.  * Side effects:
  489.  *    None.
  490.  *
  491.  *----------------------------------------------------------------------
  492.  */
  493.  
  494. #define HOST_NAME_SIZE 64
  495. #define TIME_STR_LEN 13
  496. #define SECOND_OFFSET 9
  497.  
  498. static void
  499. OutputStatus(infoPtr)
  500.     register Host_Info *infoPtr;
  501. {
  502.     MachineState state;
  503.     static char hostname[HOST_NAME_SIZE];
  504.     static char idleTime[TIME_STR_LEN];
  505.     ReturnStatus status;
  506.     char *upStr;
  507.  
  508. /*
  509.  * NOTE: the order of arguments here corresponds to the implementation
  510.  * of this routine, not to the man page!!
  511.  */
  512.     status = Sys_GetHostNameByID(infoPtr->hostID, HOST_NAME_SIZE, hostname);
  513.     if (status != SUCCESS) {
  514.     syslog(LOG_ERR, "%s: Sys_GetHostnameByID: %s\n", myName,
  515.            Stat_GetMsg(status));
  516.     Proc_Exit(status);
  517.     }
  518.  
  519.     upStr = UpString(infoPtr->timestamp, infoPtr->bootTime, &state);
  520.  
  521.     /*
  522.      * We allow migration if the file says to allow it, UpString indicated
  523.      * that the entry in the file is current, and it is the same machine type.
  524.      */
  525.     if (state == UP && infoPtr->allowMigration &&
  526.     infoPtr->archType == archType) {
  527.     state = IDLE;
  528.     }
  529.     Io_PrintStream(io_StdOut,
  530.            "%24s%1s %s %s",
  531.            hostname, (state == IDLE) ? "*" : "",
  532.            (state == DOWN) ? "down" : "  up",
  533.            upStr);
  534.     if (state != DOWN) {
  535.     Time_ToAscii(infoPtr->noInput, TRUE, idleTime);
  536.     Io_PrintStream(io_StdOut,
  537.                " %5.2lf %5.2lf %5.2lf  (idle %s)",
  538.                infoPtr->lengths[0], infoPtr->lengths[1],
  539.                infoPtr->lengths[2], idleTime);
  540.     }
  541.     Io_PrintStream(io_StdOut, "\n");
  542. }
  543.  
  544. static char *
  545. UpString(modTime, bootTime, statePtr)
  546.     int modTime;
  547.     int bootTime;
  548.     MachineState *statePtr;
  549. {
  550.     static char timeStr[TIME_STR_LEN];
  551.     int diff;
  552.  
  553.     *statePtr = UP;
  554.     /*
  555.      * See if the entry is out of date.  (Assume that anything updated
  556.      * after the current time is fairly recent and is caused by clock
  557.      * skew, so negative diffs are okay.)
  558.      */
  559.     diff = currentTime.seconds - modTime;
  560.     if (diff > timeOut) {
  561.     *statePtr = DOWN;
  562.     } else {
  563.     /*
  564.      * Now we want to know how long the machine has been up.
  565.      */
  566.     diff = modTime - bootTime;
  567.     if (diff < 0) {
  568.         Io_PrintStream(io_StdErr,
  569.                "Change was made before boot time??  modTime %d, bootTime %d.\n",
  570.                modTime, bootTime);
  571.         *statePtr = DOWN;
  572.         diff = 0;
  573.     }
  574.     }
  575.         
  576.  
  577.     Time_ToAscii(diff, TRUE, timeStr);
  578.     timeStr[SECOND_OFFSET] = '\0';
  579.     return(timeStr);
  580. }
  581.  
  582.  
  583.  
  584. /*
  585.  *----------------------------------------------------------------------
  586.  *
  587.  * ZapHostInfo --
  588.  *
  589.  *    Zero out the information for a host.
  590.  *
  591.  * Results:
  592.  *    None.
  593.  *
  594.  * Side effects:
  595.  *    The global database is modified.
  596.  *
  597.  *----------------------------------------------------------------------
  598.  */
  599.  
  600. static void
  601. ZapHostInfo(hostName)
  602.     char *hostName;
  603. {
  604.     ReturnStatus status;
  605.     Host_Info info;
  606.     Host_Entry *hostPtr;
  607.     DB_Handle sharedHandle;
  608.     
  609.  
  610.     hostPtr = Host_ByName(hostName);
  611.     if (hostPtr == (Host_Entry *) NULL) {
  612.     Io_PrintStream(io_StdErr, "ZapHostInfo: couldn't get info for %s.\n",
  613.                hostName);
  614.     return;
  615.     }
  616.     if (debug) {
  617.     Io_PrintStream(io_StdErr, "Opening shared database.\n");
  618.     Io_Flush(io_StdErr);
  619.     }
  620.     /*
  621.      * If a lock is broken, GEN_TIMEOUT is returned, and we will ignore
  622.      * that error.
  623.      */
  624.     status = Host_OpenInfo(HOST_INFO_SHARED, TRUE, &sharedHandle);
  625.     if (status != SUCCESS && status != GEN_TIMEOUT) {
  626.     Stat_PrintMsg(status, "Error in Host_OpenInfo (shared)");
  627.     Proc_Exit(status);
  628.     } else if (status == GEN_TIMEOUT) {
  629.     syslog(LOG_WARNING, "Broke lock for shared data file");
  630.     }
  631.     Byte_Zero(sizeof(info), (Address) &info);
  632.     status = Host_UpdateInfo(hostPtr->id, &info, &sharedHandle);
  633.     if (status != SUCCESS) {
  634.     syslog(LOG_ERR,
  635.            "Error %x returned from Host_UpdateInfo (shared)",
  636.            status);
  637.     Proc_Exit(status);
  638.     }
  639.     status = DB_Close(&sharedHandle);
  640.     if (status != SUCCESS) {
  641.     Io_PrintStream(io_StdErr, "%s: ZapHostInfo: error in DB_Close: %s\n",
  642.                myName, Stat_GetMsg(status));
  643.     Proc_Exit(status);
  644.     }
  645. }
  646. @
  647.  
  648.  
  649. 2.11
  650. log
  651. @Split into private and shared data files, updated at different rates.  
  652. Private used for xload, shared for migration & such.  Changed to use
  653. libc Host_* procedures.
  654. @
  655. text
  656. @d14 1
  657. a14 1
  658. static char rcsid[] = "$Header: loadAvg.c,v 2.10 88/05/15 20:44:42 douglis Exp $ SPRITE (Berkeley)";
  659. a90 1
  660. Boolean lockFile = TRUE;
  661. a91 1
  662. char *dataFile = "/sprite/spool/loadAvg/utilization";
  663. d115 1
  664. a115 1
  665.          "Output load information in verbose form."},
  666. a122 4
  667.     {OPT_FALSE, 'L', (Address)&lockFile,
  668.          "Do not lock data file during use."},
  669.     {OPT_STRING, 'o', (Address)&dataFile,
  670.          "File name to write data."},
  671. @
  672.  
  673.  
  674. 2.10
  675. log
  676. @changed to use the hostInfo C library routines and structures.
  677. @
  678. text
  679. @d14 1
  680. a14 1
  681. static char rcsid[] = "$Header: loadAvg.c,v 2.9 88/04/07 10:29:06 douglis Exp $ SPRITE (Berkeley)";
  682. d36 2
  683. a37 1
  684.  * maximum number of seconds that may pass between updating the data file.
  685. d45 1
  686. a45 1
  687. #define WRITE_INTERVAL LOAD_INTERVAL
  688. d154 2
  689. a155 1
  690. static void GetLoad();
  691. a157 1
  692. static MachineState GetStatus();
  693. d186 3
  694. d271 6
  695. a276 1
  696.     GetLoad(TRUE);
  697. d279 10
  698. a288 1
  699.     GetLoad(FALSE);
  700. d298 1
  701. a298 1
  702.  * GetLoad --
  703. d300 1
  704. a300 2
  705.  *    Output the load average of this node, all nodes, or of an idle
  706.  *    node.  If getting idle node and not verbose, just output hostID.
  707. a307 3
  708.  * Restriction: looking up this host only works for the shared file format
  709.  * for now, but that's the only way we're using it now.
  710.  *
  711. d312 1
  712. a312 2
  713. GetLoad(getIdle)
  714.     Boolean getIdle;       /* if TRUE, pick an idle node at random */
  715. a313 1
  716.     int bytesRead;
  717. a315 1
  718.     int streamID;
  719. a319 4
  720.     MachineState state;
  721.     Boolean output;
  722.     int possibleHosts[MAX_NUM_HOSTS];
  723.     int numPossible = 0;
  724. d322 1
  725. a322 1
  726.     Io_PrintStream(io_StdErr, "GetLoad called.\n");
  727. d336 1
  728. d345 1
  729. a345 1
  730.                    "GetLoad: mismatch between counter (%d) and value in data file (%d).\n",
  731. d349 1
  732. a349 10
  733.         if (!getIdle && (allHosts || i == hostID)) {
  734.         output = TRUE;
  735.         } else {
  736.         output = FALSE;
  737.         }
  738.         state = GetStatus(infoPtr, output);
  739.         if (state == IDLE) {
  740.         possibleHosts[numPossible] = i;
  741.         numPossible += 1;
  742.         }
  743. a351 3
  744.     if (verbose) {
  745.     Io_Flush(io_StdErr);
  746.     }
  747. a352 22
  748.     if (!getIdle) {
  749.     return;
  750.     }
  751.     if (debug) {
  752.     Io_PrintStream(io_StdErr, "There are %d possible idle hosts.\n",
  753.                numPossible);
  754.     Io_Flush(io_StdErr);
  755.     }
  756.     if (numPossible > 0) {
  757.     int randNum;
  758.  
  759.     Rand_InitSeed((unsigned) currentTime.microseconds);
  760.     if (numPossible > 1) {
  761.         randNum = Rand_GetValue();
  762.         randNum = randNum % numPossible;
  763.     } else {
  764.         randNum = 0;
  765.     }
  766.     Io_Print("%d\n", possibleHosts[randNum]);
  767.     } else {
  768.     Io_Print("0\n");
  769.     }
  770. d360 1
  771. a360 1
  772.  * GetStatus --
  773. d362 2
  774. a363 2
  775.  *    Determine the status of the given host;
  776.  *    if output is specified, write a "ruptime"-like record to stdout.
  777. d366 1
  778. a366 1
  779.  *    TRUE if it is permissible to migrate to the given host.
  780. d378 2
  781. a379 2
  782. static MachineState
  783. GetStatus(infoPtr, output)
  784. a380 1
  785.     Boolean output;
  786. d402 2
  787. a403 2
  788.      * We allow migration if the file says to allow it and UpString indicated
  789.      * that the entry in the file is current.
  790. d405 2
  791. a406 1
  792.     if (state == UP && infoPtr->allowMigration) {
  793. d409 7
  794. a415 1
  795.     if (output) {
  796. d417 3
  797. a419 12
  798.                "%24s%1s %s %s %s",
  799.                hostname, (state == IDLE) ? "*" : "",
  800.                (state == DOWN) ? "down" : "  up",
  801.                upStr);
  802.     if (state != DOWN) {
  803.         Time_ToAscii(infoPtr->noInput, TRUE, idleTime);
  804.         Io_PrintStream(io_StdOut,
  805.                " %5.2lf %5.2lf %5.2lf  (idle %s)",
  806.                infoPtr->lengths[0], infoPtr->lengths[1],
  807.                infoPtr->lengths[2], idleTime);
  808.     }
  809.     Io_PrintStream(io_StdOut, "\n");
  810. d421 1
  811. a421 1
  812.     return(state);
  813. a460 19
  814.  
  815. /*
  816.  *----------------------------------------------------------------------
  817.  *
  818.  * OpenCreate --
  819.  *
  820.  *    Perform an Fs_Open on a file, creating it if necessary.  (This
  821.  *    routine is needed because simply passing in FS_CREATE will cause
  822.  *    existing files to be truncated.)
  823.  *
  824.  * Results:
  825.  *    The return status from Fs_Open is returned.  A stream ID is returned
  826.  *     in *streamIDPtr.
  827.  *
  828.  * Side effects:
  829.  *    A file is opened, and it is created if it doesn't exist. 
  830.  *
  831.  *----------------------------------------------------------------------
  832.  */
  833. a461 18
  834. ReturnStatus
  835. OpenCreate(pathName, usageFlags, permissions, streamIDPtr)
  836.     char *pathName;        /* The name of the file to open */
  837.     int usageFlags;        /* FS_READ, FS_WRITE, FS_CREATE, FS_TRUNC */
  838.     int permissions;        /* Permission mask to use on creation */
  839.     int *streamIDPtr;        /* This is the user's handle on the open
  840.                  * file used in later filesystem requests */
  841. {
  842.     ReturnStatus     status;
  843.  
  844.     status = Fs_Open(pathName, usageFlags, permissions, streamIDPtr);
  845.     if (status == FS_FILE_NOT_FOUND) {
  846.     status = Fs_Open(pathName, usageFlags | FS_CREATE, permissions,
  847.              streamIDPtr);
  848.     }
  849.     return(status);
  850. }
  851.  
  852. a484 1
  853.     int streamID;
  854. a485 1
  855.     int bytesWritten;
  856. d487 1
  857. a487 1
  858.     int offset;
  859. d497 1
  860. a497 3
  861.     Io_PrintStream(io_StdErr,
  862.                "ZapHostInfo: hostID %d.  Opening file %s.\n",
  863.                hostPtr->id, dataFile);
  864. d500 7
  865. a506 4
  866.     status = Fs_Open(dataFile, FS_WRITE, 0, &streamID);
  867.     if (status != SUCCESS) {
  868.     Io_PrintStream(io_StdErr, "%s: ZapHostInfo: error opening data file: %s\n",
  869.            myName, Stat_GetMsg(status));
  870. d508 2
  871. a510 13
  872.     if (lockFile) {
  873.     if (debug) {
  874.         Io_PrintStream(io_StdErr, "ZapHostInfo: calling Ioc_Lock.\n");
  875.         Io_Flush(io_StdErr);
  876.     }
  877.     status = Ioc_Lock(streamID, IOC_LOCK_EXCLUSIVE);
  878.     if (status != SUCCESS) {
  879.         syslog(LOG_ERR, "%s: ZapHostInfo: error in Ioc_Lock: %s\n",
  880.            myName, Stat_GetMsg(status));
  881.         Proc_Exit(status);
  882.     }
  883.     }
  884.  
  885. d512 1
  886. a512 2
  887.     offset = hostPtr->id * sizeof(info);
  888.     status = Ioc_Reposition(streamID, IOC_BASE_ZERO, offset, (int *) NULL);
  889. d514 3
  890. a516 2
  891.     Io_PrintStream(io_StdErr, "%s: OutputLoads: error in Ioc_Reposition: %s\n",
  892.            myName, Stat_GetMsg(status));
  893. d519 1
  894. a519 1
  895.     status = Fs_Write(streamID, sizeof(info), (Address) &info, &bytesWritten);
  896. d521 1
  897. a521 19
  898.     Io_PrintStream(io_StdErr, "%s: ZapHostInfo: error in Fs_Read: %s\n",
  899.                myName, Stat_GetMsg(status));
  900.     Proc_Exit(status);
  901.     }
  902.     if (lockFile) {
  903.     if (debug) {
  904.         Io_PrintStream(io_StdErr, "ZapHostInfo: calling Ioc_Unlock.\n");
  905.         Io_Flush(io_StdErr);
  906.     }
  907.     status = Ioc_Unlock(streamID, IOC_LOCK_EXCLUSIVE);
  908.     if (status != SUCCESS) {
  909.         Stat_PrintMsg(status,
  910.               "ZapHostInfo: error in Ioc_Unlock");
  911.         Proc_Exit(status);
  912.     }
  913.     }
  914.     status = Fs_Close(streamID);
  915.     if (status != SUCCESS) {
  916.     Io_PrintStream(io_StdErr, "%s: ZapHostInfo: error in Fs_Close: %s\n",
  917. @
  918.  
  919.  
  920. 2.9
  921. log
  922. @Removed references to "server" and using pipes, since that's obsolete.
  923. @
  924. text
  925. @d14 1
  926. a14 1
  927. static char rcsid[] = "$Header: loadAvg.c,v 2.8 88/03/17 22:42:45 douglis Exp $ SPRITE (Berkeley)";
  928. d34 7
  929. a40 1
  930.  * command line.) 
  931. d44 2
  932. a45 2
  933. #define WRITE_INTERVAL (12 * LOAD_INTERVAL)
  934. #define TIME_OUT (3 * WRITE_INTERVAL)
  935. d305 2
  936. a306 2
  937.     register NodeInfo *infoPtr;
  938.     NodeInfo *infoArray;
  939. d319 3
  940. a321 6
  941.     if (debug) {
  942.     Io_PrintStream(io_StdErr, "GetLoad: opening file %s.\n",
  943.                dataFile);
  944.     Io_Flush(io_StdErr);
  945.     }
  946.     status = Fs_Open(dataFile, FS_READ, 0, &streamID);
  947. d323 1
  948. a323 2
  949.     syslog(LOG_ERR, "%s: GetLoad: error opening data file: %s\n",
  950.            myName, Stat_GetMsg(status));
  951. d326 3
  952. a328 11
  953.     if (lockFile) {
  954.     if (debug) {
  955.         Io_PrintStream(io_StdErr, "GetLoad: calling Ioc_Lock.\n");
  956.         Io_Flush(io_StdErr);
  957.     }
  958.     status = Ioc_Lock(streamID, IOC_LOCK_EXCLUSIVE);
  959.     if (status != SUCCESS) {
  960.         syslog(LOG_ERR, "%s: GetLoad: error in Ioc_Lock: %s\n",
  961.            myName, Stat_GetMsg(status));
  962.         Proc_Exit(status);
  963.     }
  964. d330 1
  965. a330 6
  966.     maxSize = MAX_NUM_HOSTS * sizeof(NodeInfo);
  967.     infoArray = (NodeInfo *) Mem_Alloc(maxSize);
  968.     if (debug) {
  969.     Io_PrintStream(io_StdErr, "GetLoad: calling Fs_Read.\n");
  970.     Io_Flush(io_StdErr);
  971.     }
  972. a331 20
  973.     status = Fs_Read(streamID, maxSize, (Address) infoArray, &bytesRead);
  974.     if (status != SUCCESS) {
  975.     syslog(LOG_ERR, "%s: GetLoad: error in Fs_Read: %s\n", myName,
  976.            Stat_GetMsg(status));
  977.     Proc_Exit(status);
  978.     }
  979.     if (lockFile) {
  980.     if (debug) {
  981.         Io_PrintStream(io_StdErr, "GetLoad: calling Ioc_Unlock.\n");
  982.         Io_Flush(io_StdErr);
  983.     }
  984.     status = Ioc_Unlock(streamID, IOC_LOCK_EXCLUSIVE);
  985.     if (status != SUCCESS) {
  986.         Stat_PrintMsg(status,
  987.               "GetLoad: error in Ioc_Unlock");
  988.         Proc_Exit(status);
  989.     }
  990.     }
  991.     numRecs = bytesRead / sizeof(NodeInfo);
  992.  
  993. d406 1
  994. a406 1
  995.     register NodeInfo *infoPtr;
  996. d552 1
  997. a552 1
  998.     NodeInfo info;
  999. @
  1000.  
  1001.  
  1002. 2.8
  1003. log
  1004. @Added -Z flag to zap hostname info.
  1005. @
  1006. text
  1007. @d14 1
  1008. a14 1
  1009. static char rcsid[] = "$Header: loadAvg.c,v 2.7 88/02/21 15:54:34 douglis Exp $ SPRITE (Berkeley)";
  1010. a76 1
  1011. Boolean runServer = FALSE;
  1012. a81 2
  1013. Boolean useDataFile = FALSE;
  1014. Boolean usePipes = FALSE;
  1015. a85 3
  1016. char *pipeDir = "/sprite/spool/loadAvg/daemons";
  1017. char *requestFile = "globalLoad.request";
  1018. char *responseFile = "globalLoad.response";
  1019. d107 1
  1020. a107 3
  1021.     "Run as a daemon and report load information to the global file/server."},
  1022.     {OPT_TRUE, 's', (Address)&runServer,
  1023.          "Run as a global server maintaining global state."},
  1024. a117 4
  1025.     {OPT_TRUE, 'f', (Address)&useDataFile,
  1026.     "Output options:\n\tUse shared data file for global load information (DEFAULT)."},
  1027.     {OPT_TRUE, 'p', (Address)&usePipes,
  1028.          "\tUse named pipes for global load information."},
  1029. d119 1
  1030. a119 1
  1031.          "Do not lock data file during use (ignored with -p option)."},
  1032. a121 6
  1033.     {OPT_STRING, 'P', (Address)&pipeDir,
  1034.          "Directory containing named pipes."},
  1035.     {OPT_STRING, 'r', (Address)&requestFile,
  1036.          "Request named pipe name."},
  1037.     {OPT_STRING, 'R', (Address)&responseFile,
  1038.          "Response pipe name."},
  1039. a192 9
  1040.     if (! (useDataFile || usePipes)) {
  1041.     useDataFile = TRUE;
  1042.     } else if (useDataFile && usePipes) {
  1043.     Io_PrintStream(io_StdErr,
  1044.                "%s: may only write to one of data-file or pipe.\n",
  1045.                myName);
  1046.     Proc_Exit(FAILURE);
  1047.     }
  1048.  
  1049. d197 1
  1050. a197 1
  1051.     if (! (runServer || runDaemon || getIdleNode || getLoad || zapHostInfo)) {
  1052. a204 6
  1053.     if (lockFile && !useDataFile) {
  1054.     Io_PrintStream(io_StdErr,
  1055.         "%s: may only specify lock (-l) option if writing to a data file.\n",
  1056.                myName);
  1057.     Proc_Exit(FAILURE);
  1058.     }
  1059. a259 3
  1060.     if (runServer) {
  1061.     RunServer();
  1062.     }
  1063. a294 2
  1064.     static char utilRecord[UTIL_RECORD_SIZE];
  1065.     int bytesWritten;
  1066. a295 2
  1067.     char *utilPtr;
  1068.     char *utilsPtr;
  1069. a297 1
  1070.     char fileName[FS_MAX_PATH_NAME_LENGTH];
  1071. a298 1
  1072.     NodeInfo nodeInfo;
  1073. a302 2
  1074.     double lowestLoad;
  1075.     int numScanned;
  1076. d310 6
  1077. d318 7
  1078. a324 7
  1079.  
  1080.     if (usePipes) {
  1081.         if (getLoad) {
  1082.          Sys_Panic(SYS_FATAL, "Can't get load average of local host when using pipes (yet).");
  1083.     }
  1084.     Io_PrintString(utilRecord, "%2d\n", LA_RPC_IDLE);
  1085.     Io_PrintString(fileName, "%s/%s", pipeDir, requestFile);
  1086. d326 1
  1087. a326 1
  1088.         Io_PrintStream(io_StdErr, "GetLoad: opening file %s.\n", fileName);
  1089. d329 1
  1090. a329 2
  1091.     status = OpenCreate(fileName, (FS_WRITE | FS_NAMED_PIPE_OPEN),
  1092.              OPEN_MODE, &streamID);
  1093. d331 2
  1094. a332 2
  1095.         syslog(LOG_ERR, "%s: GetLoad: error in Fs_Open: %s\n", myName,
  1096.            Stat_GetMsg(status));
  1097. d335 15
  1098. a349 16
  1099.     status = Fs_Write(streamID, UTIL_RECORD_SIZE, utilRecord,
  1100.               &bytesWritten);
  1101.     if (status != SUCCESS) {
  1102.         syslog(LOG_ERR, "%s: GetLoad: error in Fs_Write: %s\n", myName,
  1103.            Stat_GetMsg(status));
  1104.         Proc_Exit(status);
  1105.     }
  1106.     if (bytesWritten != UTIL_RECORD_SIZE) {
  1107.         syslog(LOG_ERR, "%s: GetLoad: only %d bytes written.\n",
  1108.                myName, bytesWritten);
  1109.         Proc_Exit(FAILURE);
  1110.     }
  1111.     /*
  1112.      * Need to read response from reply pipe here.
  1113.      */
  1114.     } else {
  1115. d351 1
  1116. a351 2
  1117.         Io_PrintStream(io_StdErr, "GetLoad: opening file %s.\n",
  1118.                dataFile);
  1119. d354 1
  1120. a354 1
  1121.     status = Fs_Open(dataFile, FS_READ, 0, &streamID);
  1122. d356 2
  1123. a357 2
  1124.         syslog(LOG_ERR, "%s: GetLoad: error opening data file: %s\n",
  1125.            myName, Stat_GetMsg(status));
  1126. d360 2
  1127. a361 18
  1128.     if (lockFile) {
  1129.         if (debug) {
  1130.         Io_PrintStream(io_StdErr, "GetLoad: calling Ioc_Lock.\n");
  1131.         Io_Flush(io_StdErr);
  1132.         }
  1133.         status = Ioc_Lock(streamID, IOC_LOCK_EXCLUSIVE);
  1134.         if (status != SUCCESS) {
  1135.         syslog(LOG_ERR, "%s: GetLoad: error in Ioc_Lock: %s\n",
  1136.                myName, Stat_GetMsg(status));
  1137.         Proc_Exit(status);
  1138.         }
  1139.     }
  1140.     maxSize = MAX_NUM_HOSTS * sizeof(NodeInfo);
  1141.     infoArray = (NodeInfo *) Mem_Alloc(maxSize);
  1142.     if (debug) {
  1143.         Io_PrintStream(io_StdErr, "GetLoad: calling Fs_Read.\n");
  1144.         Io_Flush(io_StdErr);
  1145.     }
  1146. d363 8
  1147. a370 10
  1148.     status = Fs_Read(streamID, maxSize, (Address) infoArray, &bytesRead);
  1149.     if (status != SUCCESS) {
  1150.         syslog(LOG_ERR, "%s: GetLoad: error in Fs_Read: %s\n", myName,
  1151.            Stat_GetMsg(status));
  1152.         Proc_Exit(status);
  1153.     }
  1154.     if (lockFile) {
  1155.         if (debug) {
  1156.         Io_PrintStream(io_StdErr, "GetLoad: calling Ioc_Unlock.\n");
  1157.         Io_Flush(io_StdErr);
  1158. d372 4
  1159. a375 5
  1160.         status = Ioc_Unlock(streamID, IOC_LOCK_EXCLUSIVE);
  1161.         if (status != SUCCESS) {
  1162.         Stat_PrintMsg(status,
  1163.                   "GetLoad: error in Ioc_Unlock");
  1164.         Proc_Exit(status);
  1165. d377 4
  1166. a380 23
  1167.     }
  1168.     numRecs = bytesRead / sizeof(NodeInfo);
  1169.     lowestLoad = MAX_LOAD;
  1170.  
  1171.     for (i = 0; i < numRecs; i++) {
  1172.         infoPtr = &infoArray[i];
  1173.         if (infoPtr->timestamp != 0) {
  1174.         if (i != infoPtr->hostID) {
  1175.             Io_PrintStream(io_StdErr,
  1176.                    "GetLoad: mismatch between counter (%d) and value in data file (%d).\n",
  1177.                    i, infoPtr->hostID);
  1178.             Proc_Exit(FAILURE);
  1179.         }
  1180.         if (!getIdle && (allHosts || i == hostID)) {
  1181.             output = TRUE;
  1182.         } else {
  1183.             output = FALSE;
  1184.         }
  1185.         state = GetStatus(infoPtr, output);
  1186.         if (state == IDLE) {
  1187.             possibleHosts[numPossible] = i;
  1188.             numPossible += 1;
  1189.         }
  1190. d383 15
  1191. a397 14
  1192.     if (verbose) {
  1193.         Io_Flush(io_StdErr);
  1194.     }
  1195.     Mem_Free((Address) infoArray);
  1196.     if (!getIdle) {
  1197.         return;
  1198.     }
  1199.     if (debug) {
  1200.         Io_PrintStream(io_StdErr, "There are %d possible idle hosts.\n",
  1201.                numPossible);
  1202.         Io_Flush(io_StdErr);
  1203.     }
  1204.     if (numPossible > 0) {
  1205.         int randNum;
  1206. d399 4
  1207. a402 8
  1208.         Rand_InitSeed((unsigned) currentTime.microseconds);
  1209.         if (numPossible > 1) {
  1210.         randNum = Rand_GetValue();
  1211.         randNum = randNum % numPossible;
  1212.         } else {
  1213.         randNum = 0;
  1214.         }
  1215.         Io_Print("%d\n", possibleHosts[randNum]);
  1216. d404 1
  1217. a404 1
  1218.         Io_Print("0\n");
  1219. d406 3
  1220. @
  1221.  
  1222.  
  1223. 2.7
  1224. log
  1225. @Changed to use syslog.
  1226. @
  1227. text
  1228. @d14 1
  1229. a14 1
  1230. static char rcsid[] = "$Header: loadAvg.c,v 2.6 87/12/02 12:02:46 douglis Exp $ SPRITE (Berkeley)";
  1231. d24 1
  1232. d88 1
  1233. d146 2
  1234. d166 1
  1235. d224 1
  1236. a224 1
  1237.     if (! (runServer || runDaemon || getIdleNode || getLoad)) {
  1238. d285 5
  1239. d636 95
  1240. @
  1241.  
  1242.  
  1243. 2.6
  1244. log
  1245. @Print out uptime & idle time using Time_ToAscii.  Fixed bug w/
  1246. loadAvg/rup/... defaults.  (Now rup implies getLoad & getAllHosts and 
  1247. anything else implies loadAvg of local host.)
  1248.  
  1249. ToDo: allow host names, a la "rup" under unix.
  1250. @
  1251. text
  1252. @d14 1
  1253. a14 1
  1254. static char rcsid[] = "$Header: loadAvg.c,v 2.5 87/12/01 20:52:50 douglis Exp $ SPRITE (Berkeley)";
  1255. d23 1
  1256. d101 2
  1257. d199 2
  1258. d211 1
  1259. a211 1
  1260.                argv[0]);
  1261. d220 1
  1262. a220 1
  1263.     if (String_FindSubstring(argv[0], "rup") != NULL) {
  1264. d230 1
  1265. a230 1
  1266.                argv[0]);
  1267. d265 2
  1268. a266 1
  1269.     Stat_PrintMsg(status, "Error in Sys_GetMachineInfo");
  1270. d271 2
  1271. a272 1
  1272.     Stat_PrintMsg(status, "Error in Sys_GetTimeOfDay");
  1273. d360 2
  1274. a361 1
  1275.         Stat_PrintMsg(status, "GetLoad: error in Fs_Open");
  1276. d367 2
  1277. a368 1
  1278.         Stat_PrintMsg(status, "GetLoad: error in Fs_Write");
  1279. d372 2
  1280. a373 2
  1281.         Io_PrintStream(io_StdErr, "GetLoad: only %d bytes written.\n",
  1282.                bytesWritten);
  1283. d387 2
  1284. a388 1
  1285.         Stat_PrintMsg(status, "GetLoad: error opening data file");
  1286. d398 2
  1287. a399 1
  1288.         Stat_PrintMsg(status, "GetLoad: error in Ioc_Lock");
  1289. d412 2
  1290. a413 1
  1291.         Stat_PrintMsg(status, "GetLoad: error in Fs_Read");
  1292. d521 2
  1293. a522 1
  1294.     Stat_PrintMsg(status, "Sys_GetHostnameByID");
  1295. d537 1
  1296. a537 1
  1297.                "%18s%1s %s %s %s",
  1298. @
  1299.  
  1300.  
  1301. 2.5
  1302. log
  1303. @Changed to stop complaining if the update time is later than our idea
  1304. of the current time.
  1305. @
  1306. text
  1307. @d14 1
  1308. a14 1
  1309. static char rcsid[] = "$Header: loadAvg.c,v 2.4 87/11/20 12:40:01 douglis Exp $ SPRITE (Berkeley)";
  1310. d214 2
  1311. a215 2
  1312.     if (! (runServer || runDaemon || getIdleNode)) {
  1313.     if (String_FindSubstring(argv[0], "loadAvg") != NULL) {
  1314. a216 2
  1315.     } else     if (String_FindSubstring(argv[0], "rup") != NULL) {
  1316.         getLoad = TRUE;
  1317. d219 1
  1318. a219 2
  1319.         Opt_PrintUsage(argv[0], numOptions, optionArray);
  1320.         Proc_Exit(FAILURE);
  1321. d489 3
  1322. d499 1
  1323. d524 1
  1324. a524 1
  1325.                "%20s%1s %s",
  1326. d526 1
  1327. d529 1
  1328. d531 1
  1329. a531 1
  1330.                " %5.2lf %5.2lf %5.2lf (%d)",
  1331. d533 1
  1332. a533 1
  1333.                infoPtr->lengths[2], infoPtr->noInput);
  1334. a539 5
  1335. #define UP_STR_LEN 64
  1336. #define SECS_PER_MIN 60
  1337. #define MINS_PER_HOUR 60
  1338. #define HOURS_PER_DAY 24
  1339.  
  1340. d546 1
  1341. a546 5
  1342.     static char str[UP_STR_LEN];
  1343.     Boolean up = TRUE;
  1344.     int minutes;
  1345.     int hours;
  1346.     int days;
  1347. a556 1
  1348.     up = FALSE;
  1349. a566 1
  1350.         Io_PrintString(str, "????     ??:??");
  1351. d568 1
  1352. a568 1
  1353.         return(str);
  1354. a571 5
  1355.     minutes = (diff + SECS_PER_MIN - 1) / SECS_PER_MIN;
  1356.     hours = minutes / MINS_PER_HOUR;
  1357.     minutes = minutes % MINS_PER_HOUR;
  1358.     days = hours / HOURS_PER_DAY;
  1359.     hours = hours % HOURS_PER_DAY;
  1360. d573 3
  1361. a575 4
  1362.     Io_PrintString(str, "%4s %3d+%02d:%02d",
  1363.            up ? "up" : "down",
  1364.            days, hours, minutes);
  1365.     return(str);
  1366. @
  1367.  
  1368.  
  1369. 2.4
  1370. log
  1371. @Made it emulate "ruptime", use host names instead of numbers for load avg.
  1372. @
  1373. text
  1374. @d14 1
  1375. a14 1
  1376. static char rcsid[] = "$Header: loadAvg.c,v 2.3 87/11/19 19:52:47 douglis Exp $ SPRITE (Berkeley)";
  1377. d556 5
  1378. a561 15
  1379.     if (diff < 0) {
  1380.     /*
  1381.      * If just a little off, assume clock skew and permit the entry.
  1382.      */
  1383.     if (diff >= -10) {
  1384.         diff = 0;
  1385.     } else {
  1386.         Io_PrintStream(io_StdErr,
  1387.                "Entry updated before current time: currentTime %d,   modTime %d.\n",
  1388.                currentTime.seconds, modTime);
  1389.         Io_PrintString(str, "????     ??:??");
  1390.         *statePtr = DOWN;
  1391.         return(str);
  1392.     }
  1393.     }
  1394. d566 3
  1395. @
  1396.  
  1397.  
  1398. 2.3
  1399. log
  1400. @decreased WRITE_INTERVAL.  Moved to /sprite/spool/loadAvg.  Changed
  1401. around some options.  Changed to allow getting load avg of current
  1402. node, all nodes.  Fixed bug with closing file w/o unlocking it,
  1403. not keeping valid offset value.
  1404. @
  1405. text
  1406. @d6 2
  1407. a7 1
  1408.  *    or as a stand-alone program (to return the load of the local host).
  1409. d14 1
  1410. a14 1
  1411. static char rcsid[] = "$Header: loadAvg.c,v 2.1 87/03/11 18:12:13 douglis Exp $ SPRITE (Berkeley)";
  1412. d22 1
  1413. d72 1
  1414. d101 2
  1415. d104 1
  1416. a104 1
  1417.          "Get the load average of this node (DEFAULT)."},
  1418. d144 10
  1419. d155 1
  1420. d157 1
  1421. d159 2
  1422. d162 1
  1423. d215 9
  1424. a223 1
  1425.     getLoad = TRUE;
  1426. d258 4
  1427. a261 1
  1428.     status = Sys_GetMachineInfo(NULL, NULL, &hostID);
  1429. d266 5
  1430. d283 1
  1431. a283 1
  1432.     GetLoad(FALSE);
  1433. d286 1
  1434. a286 1
  1435.     GetLoad(TRUE);
  1436. d298 2
  1437. a299 2
  1438.  *    Output the load average of this node or of an idle node.  If getting
  1439.  *    idle node and not verbose, just output hostID.
  1440. d314 2
  1441. a315 2
  1442. GetLoad(thisHost)
  1443.     Boolean thisHost;       /* if TRUE, just look up this host */
  1444. d333 2
  1445. a334 1
  1446.     Time currentTime;
  1447. d344 1
  1448. a344 1
  1449.         if (thisHost) {
  1450. d381 1
  1451. a381 1
  1452.         Stat_PrintMsg(status, "GetLoad: error in Fs_Open");
  1453. a420 1
  1454.     Sys_GetTimeOfDay(¤tTime, NULL, NULL);
  1455. d425 3
  1456. a427 4
  1457.             if (currentTime.seconds - infoPtr->timestamp <= timeOut) {
  1458.             if (i != infoPtr->hostID) {
  1459.             Io_PrintStream(io_StdErr,
  1460.          "GetLoad: mismatch between counter (%d) and value in data file (%d).\n",
  1461. d429 1
  1462. a429 18
  1463.             Proc_Exit(FAILURE);
  1464.             }
  1465.             if (verbose || (thisHost && i == hostID)) {
  1466.             Io_PrintStream(io_StdErr,
  1467.                        "Node %d\tTime %d\tload average %5.2lf %5.2lf %5.2lf\tidle %d\t Allow = %d.\n",
  1468.                        infoPtr->hostID, infoPtr->timestamp, 
  1469.                        infoPtr->lengths[0], infoPtr->lengths[1],
  1470.                        infoPtr->lengths[2], infoPtr->noInput,
  1471.                        infoPtr->allowMigration);
  1472.             }
  1473.     
  1474.             if (infoPtr->allowMigration) {
  1475.             possibleHosts[numPossible] = i;
  1476.             numPossible += 1;
  1477.             }
  1478.         } else if (debug || verbose || (thisHost && i == hostID)) {
  1479.              Io_PrintStream(io_StdErr, "Node %d has old information: current time %d, time updated %d.\n", 
  1480.              i, currentTime.seconds, infoPtr->timestamp);
  1481. d431 10
  1482. d447 1
  1483. a447 1
  1484.     if (thisHost) {
  1485. d472 126
  1486. @
  1487.  
  1488.  
  1489. 2.2
  1490. log
  1491. @Combined thresholds into a single structure.  Added getting random node.
  1492. @
  1493. text
  1494. @d18 1
  1495. d34 1
  1496. a34 1
  1497. #define WRITE_INTERVAL (60 * LOAD_INTERVAL)
  1498. d70 1
  1499. d83 1
  1500. a83 1
  1501. char *pipeDir = "/etc/daemons";
  1502. d86 1
  1503. a86 1
  1504. char *dataFile = "/etc/utilization";
  1505. d98 4
  1506. a101 2
  1507.     {OPT_TRUE, 'g', (Address)&getIdleNode,
  1508.          "Get the hostID of an idle node (DEFAULT)."},
  1509. d109 1
  1510. a109 1
  1511.     {OPT_INT, 'l', (Address)&loadInterval,
  1512. d117 1
  1513. a117 1
  1514.     "Output options:\n\tUse shared data file for global load information."},
  1515. d123 1
  1516. a123 1
  1517.          "File name to write data (default \"/etc/utilization\")."},
  1518. d125 1
  1519. a125 1
  1520.          "Directory containing named pipes (default \"/etc/daemons\")."},
  1521. d127 1
  1522. a127 1
  1523.          "Request named pipe name (default \"globalLoad.request\")."},
  1524. d129 3
  1525. a131 3
  1526.          "Response pipe name (default \"globalLoad.response\")."},
  1527.     {OPT_INT, 'i', (Address)&thresholds.noInput,
  1528.          "Minimum idle time to allow foreign procs (default 30s)."},
  1529. d133 1
  1530. a133 1
  1531.          "Maximum load average to allow foreign procs (default 0.3)."},
  1532. d141 1
  1533. a141 1
  1534. static void GetIdleNode();
  1535. d191 1
  1536. a191 1
  1537.      * Default operation is to get an idle node, using a global data file.
  1538. d195 1
  1539. a195 4
  1540.     getIdleNode = TRUE;
  1541.     if (! usePipes) {
  1542.         useDataFile = TRUE;
  1543.     }
  1544. d236 4
  1545. d247 1
  1546. a247 1
  1547.     GetIdleNode();
  1548. d249 3
  1549. d260 1
  1550. a260 1
  1551.  * GetIdleNode --
  1552. d262 2
  1553. a263 1
  1554.  *    Output the hostID of an idle node.
  1555. d269 1
  1556. a269 1
  1557.  *    The ID is written to io_StdOut.
  1558. d271 3
  1559. d278 2
  1560. a279 1
  1561. GetIdleNode()
  1562. d302 1
  1563. a302 1
  1564.     Io_PrintStream(io_StdErr, "GetIdleNode called.\n");
  1565. d307 3
  1566. d313 1
  1567. a313 1
  1568.         Io_PrintStream(io_StdErr, "GetIdleNode: opening file %s.\n", fileName);
  1569. d319 1
  1570. a319 1
  1571.         Stat_PrintMsg(status, "GetIdleNode: error in Fs_Open");
  1572. d325 1
  1573. a325 1
  1574.         Stat_PrintMsg(status, "GetIdleNode: error in Fs_Write");
  1575. d329 1
  1576. a329 1
  1577.         Io_PrintStream(io_StdErr, "GetIdleNode: only %d bytes written.\n",
  1578. d338 1
  1579. a338 1
  1580.         Io_PrintStream(io_StdErr, "GetIdleNode: opening file %s.\n",
  1581. d344 1
  1582. a344 1
  1583.         Stat_PrintMsg(status, "GetIdleNode: error in Fs_Open");
  1584. d349 1
  1585. a349 1
  1586.         Io_PrintStream(io_StdErr, "GetIdleNode: calling Fs_Lock.\n");
  1587. d352 1
  1588. a352 1
  1589.         status = Fs_Lock(streamID, FS_LOCK_EXCLUSIVE);
  1590. d354 1
  1591. a354 1
  1592.         Stat_PrintMsg(status, "GetIdleNode: error in Fs_Lock");
  1593. d361 1
  1594. a361 1
  1595.         Io_PrintStream(io_StdErr, "GetIdleNode: calling Fs_Read.\n");
  1596. d367 1
  1597. a367 1
  1598.         Stat_PrintMsg(status, "GetIdleNode: error in Fs_Read");
  1599. d372 1
  1600. a372 1
  1601.         Io_PrintStream(io_StdErr, "GetIdleNode: calling Fs_(Un)Lock.\n");
  1602. d375 1
  1603. a375 1
  1604.         status = Fs_Lock(streamID, FS_LOCK_EXCLUSIVE | FS_UNLOCK);
  1605. d378 1
  1606. a378 1
  1607.                   "GetIdleNode: error in Fs_Lock while unlocking file");
  1608. d388 24
  1609. a411 7
  1610.         if (infoPtr->timestamp != 0 &&
  1611.         (currentTime.seconds - infoPtr->timestamp <= timeOut)) {
  1612.         if (i != infoPtr->hostID) {
  1613.             Io_PrintStream(io_StdErr,
  1614.      "GetIdleNode: mismatch between counter (%d) and value in data file (%d).\n",
  1615.                    i, infoPtr->hostID);
  1616.             Proc_Exit(FAILURE);
  1617. a412 13
  1618.         if (verbose) {
  1619.             Io_PrintStream(io_StdErr,
  1620.                    "Node %d\tTime %d\tload average %5.2lf %5.2lf %5.2lf\tidle %d\t Allow = %d.\n",
  1621.                    infoPtr->hostID, infoPtr->timestamp, 
  1622.                    infoPtr->lengths[0], infoPtr->lengths[1],
  1623.                    infoPtr->lengths[2], infoPtr->noInput,
  1624.                    infoPtr->allowMigration);
  1625.         }
  1626.  
  1627.         if (infoPtr->allowMigration) {
  1628.             possibleHosts[numPossible] = i;
  1629.             numPossible += 1;
  1630.         }
  1631. d419 3
  1632. d429 2
  1633. a430 1
  1634.         
  1635. d438 2
  1636. @
  1637.  
  1638.  
  1639. 2.1
  1640. log
  1641. @Keep track of whether to migrate processes based on load average
  1642. and keyboard/mouse idle time.
  1643. @
  1644. text
  1645. @d13 1
  1646. a13 1
  1647. static char rcsid[] = "$Header: loadAvg.c,v 2.0 87/03/11 12:39:41 douglis Exp $ SPRITE (Berkeley)";
  1648. d19 1
  1649. d22 31
  1650. a52 4
  1651.  * Define arbitrary limits.  Accept migrated processes if the load average
  1652.  * is below THRESHOLD_LOW and stop accepting them if it goes over
  1653.  * THRESHOLD_HIGH.  INPUT_THRESHOLD is the number of seconds that a node must
  1654.  * be idle for it to accept migrated processes.  (Set to 60 seconds for
  1655. d58 4
  1656. a61 2
  1657. #define THRESHOLD_HIGH 0.8
  1658. #define INPUT_THRESHOLD 60
  1659. d63 6
  1660. d72 1
  1661. d75 1
  1662. d85 8
  1663. a92 4
  1664. char *weightString = NULL;
  1665. double weights[] = {WEIGHT1, WEIGHT2, WEIGHT3};
  1666. int inputThreshold = INPUT_THRESHOLD;
  1667. double queueThreshold[] = {THRESHOLD_LOW, THRESHOLD_HIGH};
  1668. d103 8
  1669. a110 4
  1670.     {OPT_INT, 'i', (Address)&loadInterval,
  1671.     "Interval between iterations for getting load info (default 5 seconds)"},
  1672.     {OPT_INT, 'I', (Address)&writeInterval,
  1673.          "Interval between outputting load info (default 5 seconds)"},
  1674. d116 1
  1675. a116 1
  1676.     {OPT_TRUE, 'L', (Address)&lockFile,
  1677. d126 4
  1678. d131 1
  1679. a131 3
  1680.          "Specify two limits for migration (as in the form '-T \"0.3 0.8\"')."},
  1681.     {OPT_STRING, 'W', (Address)&weightString,
  1682.          "Specify three weights for exponential averaging (as in the form '-W \".2 .5 .9\"')."},
  1683. d164 1
  1684. d203 3
  1685. a205 7
  1686.     if (weightString) {
  1687.     numScanned = Io_ScanString(weightString, "%f %f %f",
  1688.                    &weights[0], &weights[1], &weights[2]);
  1689.     if (numScanned < 3) {
  1690.         Io_PrintStream(io_StdErr, "%s: Invalid weights '%s'.\n",
  1691.                weightString);
  1692.         Proc_Exit(FAILURE);
  1693. d208 1
  1694. a208 1
  1695.  
  1696. d210 4
  1697. a213 3
  1698.     numScanned = Io_ScanString(thresholdString, "%lf %lf",
  1699.                    &queueThreshold[0], &queueThreshold[1]);
  1700.     if (numScanned < 2) {
  1701. d278 2
  1702. a279 1
  1703.     NodeInfo *infoPtr;
  1704. d284 3
  1705. d297 1
  1706. a297 1
  1707.         Io_PrintStream(io_StdErr, "Opening file %s.\n", fileName);
  1708. d303 1
  1709. a303 1
  1710.         Stat_PrintMsg(status, "Error in Fs_Open");
  1711. d309 1
  1712. a309 1
  1713.         Stat_PrintMsg(status, "Error in Fs_Write");
  1714. d313 1
  1715. a313 1
  1716.         Io_PrintStream(io_StdErr, "Only %d bytes written.\n",
  1717. d322 2
  1718. a323 1
  1719.         Io_PrintStream(io_StdErr, "Opening file %s.\n", dataFile);
  1720. d328 1
  1721. a328 1
  1722.         Stat_PrintMsg(status, "Error in Fs_Open");
  1723. d332 4
  1724. d338 1
  1725. a338 1
  1726.         Stat_PrintMsg(status, "Error in Fs_Lock");
  1727. d343 7
  1728. a349 2
  1729.     infoPtr = (NodeInfo *) Mem_Alloc(maxSize);
  1730.     status = Fs_Read(streamID, maxSize, (Address) infoPtr, &bytesRead);
  1731. d351 1
  1732. a351 1
  1733.         Stat_PrintMsg(status, "Error in Fs_Read");
  1734. d355 4
  1735. d361 2
  1736. a362 1
  1737.         Stat_PrintMsg(status, "Error in Fs_Lock while unlocking file");
  1738. d368 2
  1739. d371 4
  1740. a374 2
  1741.         if (infoPtr[i].timestamp  != 0) {
  1742.         if (i != infoPtr[i].hostID) {
  1743. d376 2
  1744. a377 2
  1745.      "Mismatch between counter (%d) and value in data file (%d).\n",
  1746.                    i, infoPtr[i].hostID);
  1747. d380 13
  1748. a392 9
  1749.         Io_Print(
  1750.     "Node %d\tTime %d\tload average %5.2lf %5.2lf %5.2lf\tidle %d\t Allow = %d.\n",
  1751.              infoPtr[i].hostID, infoPtr[i].timestamp, 
  1752.              infoPtr[i].lengths[0], infoPtr[i].lengths[1],
  1753.              infoPtr[i].lengths[2], infoPtr[i].noInput,
  1754.              infoPtr[i].allowMigration);
  1755.         /*
  1756.          * Should retain info for lowest avg node.
  1757.          */
  1758. d395 20
  1759. a414 1
  1760.     Mem_Free((Address) infoPtr);
  1761. @
  1762.  
  1763.  
  1764. 2.0
  1765. log
  1766. @Split into header file & separate modules (daemon, server, & 
  1767. loadAvg (main)).  
  1768. @
  1769. text
  1770. @d13 1
  1771. a13 1
  1772. static char rcsid[] = "$Header: loadAvg.c,v 1.8 87/03/11 11:09:50 douglis Exp $ SPRITE (Berkeley)";
  1773. d20 13
  1774. a39 1
  1775. Boolean writeToStdOut = FALSE;
  1776. d42 1
  1777. a42 1
  1778. Boolean lockFile = FALSE;
  1779. d49 3
  1780. a69 2
  1781.     {OPT_TRUE, 'S', (Address)&writeToStdOut,
  1782.          "\tOutput daemon's info to standard output (for debugging)."},
  1783. d71 1
  1784. a71 1
  1785.          "Lock data file during use (not valid with -p or -s options)."},
  1786. d80 2
  1787. d83 1
  1788. a83 1
  1789.          "Specify three weights for exponential averaging (as in the form '-w \".2 .5 .9\"')."},
  1790. d128 1
  1791. a128 1
  1792.     if (! (useDataFile || usePipes || writeToStdOut)) {
  1793. d164 10
  1794. d232 1
  1795. d239 2
  1796. a240 1
  1797.     Io_Print("GetIdleNode called.\n");
  1798. d287 3
  1799. a289 3
  1800.     maxSize = MAX_NUM_HOSTS * UTIL_RECORD_SIZE;
  1801.     utilsPtr = Mem_Alloc(maxSize);
  1802.     status = Fs_Read(streamID, maxSize, utilsPtr, &bytesRead);
  1803. d301 1
  1804. a301 1
  1805.     numRecs = bytesRead / UTIL_RECORD_SIZE;
  1806. d303 3
  1807. a305 15
  1808.     for (i = 0, utilPtr = utilsPtr; i < numRecs;
  1809.          i++, utilPtr += UTIL_RECORD_SIZE) {
  1810.         if (*utilPtr != '\0') {
  1811.         numScanned = Io_ScanString(utilPtr,
  1812.                "%*d %d %d %d %d %d %d %lf %lf %lf",
  1813.                &hostID,
  1814.                &nodeInfo.timestamp,
  1815.                &nodeInfo.noInput,
  1816.                &nodeInfo.utils[0],
  1817.                &nodeInfo.utils[1],
  1818.                &nodeInfo.utils[2],
  1819.                &nodeInfo.lengths[0],
  1820.                &nodeInfo.lengths[1],
  1821.                &nodeInfo.lengths[2]);
  1822.         if (numScanned != 9) {
  1823. a306 8
  1824.      "Error scanning data for node %d.  Scanned only %d items.\n",
  1825.                    i, numScanned);
  1826. #ifdef notdef
  1827.             Proc_Exit(FAILURE);
  1828. #endif
  1829.         }
  1830.         if (i != hostID) {
  1831.             Io_PrintStream(io_StdErr,
  1832. d308 1
  1833. a308 1
  1834.                    i, hostID);
  1835. d311 6
  1836. a316 2
  1837.         Io_Print("Node %d\tload average %5.2lf\tidle %d.\n", hostID,
  1838.              nodeInfo.lengths[2], nodeInfo.noInput);
  1839. d322 1
  1840. a322 1
  1841.     Mem_Free(utilsPtr);
  1842. d346 1
  1843. a346 1
  1844. static ReturnStatus
  1845. @
  1846.  
  1847.  
  1848. 1.8
  1849. log
  1850. @Changed file opens to use CREATE flag only if file is not found. 
  1851. Keep track of time since last keyboard/mouse input.
  1852. @
  1853. text
  1854. @d13 1
  1855. a13 1
  1856. static char rcsid[] = "$Header: loadAvg.c,v 1.7 87/03/09 12:14:30 douglis Exp $ SPRITE (Berkeley)";
  1857. d17 1
  1858. a17 8
  1859. #include "sprite.h"
  1860. #include "fs.h"
  1861. #include "sync.h"
  1862. #include "status.h"
  1863. #include "io.h"
  1864. #include "proc.h"
  1865. #include "rpc.h"
  1866. #include "kernel/sched.h"
  1867. a18 3
  1868. #include "ioc.h"
  1869. #include "byte.h"
  1870. #include "mem.h"
  1871. a19 39
  1872. /*
  1873.  * Define pseudo-RPC protocol for named pipes.
  1874.  *
  1875.  *    LA_RPC_UPDATE        - update load statistics for a node
  1876.  *    LA_RPC_IDLE        - get an idle node
  1877.  *    LA_RPC_ALLINFO        - output statistics for all nodes
  1878.  */
  1879.  
  1880. #define LA_RPC_UPDATE 0
  1881. #define LA_RPC_IDLE 1
  1882. #define LA_RPC_ALL_INFO 2
  1883.  
  1884. /*
  1885.  * Define constants specific to load average statistics.
  1886.  */
  1887.  
  1888. #define LOAD_INTERVAL 5
  1889. #define WRITE_INTERVAL (1 * LOAD_INTERVAL)
  1890. #define WEIGHT1 (double) 0.9200444146293232     /* exp(-1/12) */
  1891. #define WEIGHT2 (double) 0.9834714538216174     /* exp(-1/60) */
  1892. #define WEIGHT3 (double) 0.9944598480048967     /* exp(-1/180) */
  1893. #define LOAD_NUM_VALUES 3
  1894.  
  1895. /*
  1896.  * Define constants related to Sprite system characteristics and defaults.
  1897.  */
  1898.  
  1899. #define STANDARD_OUTPUT 1
  1900. #define OPEN_MODE 0664
  1901. #define MAX_NUM_HOSTS 256
  1902.  
  1903. /*
  1904.  * A record contains "%2d %3d %10d %10d %3.0f %3.0f %3.0f %5.2f %5.2f %5.2f\n",
  1905.  * plus a null byte.  (This amounts to 54 bytes.)  Make it the next
  1906.  * power of 2.
  1907.  */
  1908.  
  1909. #define UTIL_RECORD_SIZE 64
  1910.  
  1911. d70 1
  1912. a70 1
  1913. int numOptions = sizeof(optionArray) / sizeof(Option);
  1914. d72 1
  1915. a72 4
  1916. /*
  1917.  * Information maintained by the local daemon, containing scheduler statistics
  1918.  * at some instant in time.
  1919.  */
  1920. d74 1
  1921. a74 5
  1922. typedef struct {
  1923.     int     lowTicks;
  1924.     int     highTicks;
  1925.     int        queueLength;
  1926. } Stats;
  1927. a75 38
  1928. /*
  1929.  * Keep track of both utilization and ready-queue length when load
  1930.  * averages are used.
  1931.  */
  1932.  
  1933. typedef struct {
  1934.     double     utilization;
  1935.     double    queueLength;
  1936. } Load;
  1937.  
  1938. /*
  1939.  * For each machine, keep track of the timestamp for its information and the
  1940.  * different load averages reported.  (Used only by the server.)
  1941.  */
  1942.  
  1943. typedef struct {
  1944.     int            utils[LOAD_NUM_VALUES];
  1945.     double        lengths[LOAD_NUM_VALUES];
  1946.     int     timestamp;
  1947.     int     noInput;
  1948. } NodeInfo;
  1949.  
  1950. #define HIGH_TO_LOW_TICKS ((unsigned)0xffffffff)
  1951. #define AND3(a, b, c) (((a) && (b)) || ((a) && (c)) || ((b) && (c)))
  1952.  
  1953. void RunDaemon();
  1954. void RunServer();
  1955. void GetStats();
  1956. void PrintAllInfo();
  1957. void OutputLoads();
  1958. void CalculateLoads();
  1959. void GetIdleNode();
  1960. void UpdateData();
  1961. static ReturnStatus OpenCreate();
  1962.  
  1963. static unsigned int maxIdle;
  1964. int hostID;
  1965.  
  1966. a180 549
  1967.  * RunDaemon --
  1968.  *
  1969.  *    (Optionally) fork a child to be the local daemon.  This daemon will
  1970.  *    periodically send load information to a global server using named
  1971.  *    pipes.
  1972.  *
  1973.  * Results:
  1974.  *    None.
  1975.  *
  1976.  * Side effects:
  1977.  *    A second process may be created.
  1978.  *
  1979.  *----------------------------------------------------------------------
  1980.  */
  1981.  
  1982. void
  1983. RunDaemon()
  1984. {
  1985.     ReturnStatus status;
  1986.     Time sleepTime;
  1987.     Time time;
  1988.     Load loads[LOAD_NUM_VALUES];
  1989.     Proc_PID pid;
  1990.     int streamID;
  1991.     char *fileName;
  1992.     char fileNameBuffer[FS_MAX_PATH_NAME_LENGTH];
  1993.     int flags = FS_WRITE;
  1994.     int mode = OPEN_MODE;
  1995.     Stats stats[2];
  1996.     int nextStat;
  1997.     int iterationNumber;
  1998.     int writeRate;
  1999.     int noInput;
  2000.  
  2001.  
  2002.     if (forkChild) {
  2003.     status = Proc_Fork(FALSE, &pid);
  2004.     } else {
  2005.     status = PROC_CHILD_PROC;
  2006.     }
  2007.     if (status == PROC_CHILD_PROC) {
  2008.     sleepTime.seconds = loadInterval;
  2009.     sleepTime.microseconds = 0;
  2010.  
  2011.     if (useDataFile || usePipes) {
  2012.         if (useDataFile) {
  2013.         fileName = dataFile;
  2014.         } else {
  2015.         fileName = fileNameBuffer;
  2016.         Io_PrintString(fileName, "%s/%s", pipeDir, requestFile);
  2017.         flags |= FS_NAMED_PIPE_OPEN;
  2018.         }
  2019.         if (debug) {
  2020.         Io_PrintStream(io_StdErr, "Opening file %s.\n", fileName);
  2021.         Io_Flush(io_StdErr);
  2022.         }
  2023.         status = OpenCreate(fileName, flags, mode, &streamID);
  2024.         if (status != SUCCESS) {
  2025.         Stat_PrintMsg(status, "Error in Fs_Open");
  2026.         Proc_Exit(status);
  2027.         }
  2028.     } else {
  2029.         streamID = STANDARD_OUTPUT;
  2030.     }
  2031.  
  2032.     /*
  2033.      * Get the initial load value.
  2034.      */
  2035.  
  2036.     GetStats(&stats[0], (Time *) NULL, &noInput);
  2037.     status = Sync_WaitTime(sleepTime);
  2038.     if (status != SUCCESS) {
  2039.         Proc_Exit(status);
  2040.     }
  2041.     nextStat = 1;
  2042.     iterationNumber = 0;
  2043.     writeRate = writeInterval / loadInterval;
  2044.  
  2045.     while(TRUE) {
  2046.         GetStats(&stats[nextStat], &time, &noInput);
  2047.         nextStat = (nextStat + 1) % 2;
  2048.         CalculateLoads(stats, nextStat, loads);
  2049.         if (iterationNumber == 0) {
  2050.         OutputLoads(streamID, loads, time);
  2051.         }
  2052.         iterationNumber = (iterationNumber + 1) % writeRate;
  2053.         status = Sync_WaitTime(sleepTime);
  2054.         if (status != SUCCESS) {
  2055.         Proc_Exit(status);
  2056.         }
  2057.     }
  2058.     } else if (status != SUCCESS) {
  2059.     Stat_PrintMsg(status, "Error in Proc_Fork");
  2060.     Proc_Exit(status);
  2061.     }
  2062. }
  2063.  
  2064.  
  2065. /*
  2066.  *----------------------------------------------------------------------
  2067.  *
  2068.  * CalculateLoads --
  2069.  *
  2070.  *    Given the number of idle ticks at two different times, calculate
  2071.  *    the utilization of the computer during that period of time and
  2072.  *    average with weighted values of utilization over different times.
  2073.  *
  2074.  *    The same calculation is performed for ready queue length.
  2075.  *
  2076.  * Results:
  2077.  *    The calculated utilization & average queue lengths are returned in
  2078.  *    loads[0..LOAD_NUM_VALUES].
  2079.  *
  2080.  * Side effects:
  2081.  *    None.
  2082.  *
  2083.  *----------------------------------------------------------------------
  2084.  */
  2085.  
  2086. void
  2087. CalculateLoads(stats, nextStat, loads)
  2088.     Stats stats[];
  2089.     int nextStat;
  2090.     Load loads[];
  2091. {
  2092.     double currentLoad;
  2093.     register Stats *oldStatsPtr;
  2094.     register Stats *newStatsPtr;
  2095.     unsigned lowTicks;
  2096.     int i;
  2097.     static Boolean init = FALSE;
  2098.  
  2099.     if (nextStat == 0) {
  2100.     oldStatsPtr = stats;
  2101.     newStatsPtr = &(stats[1]);
  2102.     } else {
  2103.     newStatsPtr = stats;
  2104.     oldStatsPtr = &(stats[1]);
  2105.     }
  2106.     if (newStatsPtr->highTicks != oldStatsPtr->highTicks) {
  2107.     lowTicks =  HIGH_TO_LOW_TICKS - oldStatsPtr->lowTicks +
  2108.         newStatsPtr->lowTicks;
  2109.     } else {
  2110.     lowTicks = newStatsPtr->lowTicks - oldStatsPtr->lowTicks;
  2111.     }
  2112.  
  2113. #define DEBUG
  2114. #ifdef DEBUG
  2115.     if (debug) {
  2116.     Io_PrintStream(io_StdErr, "Lowticks=%d.\n", lowTicks);
  2117.     }
  2118. #endif
  2119.     /*
  2120.      * Since we don't get an absolute record of the time, it is possible
  2121.      * to sleep a little too long and wind up with lowTicks > maxIdle.
  2122.      */
  2123.  
  2124.     if (lowTicks > maxIdle) {
  2125.     currentLoad = 0.;
  2126.     } else {
  2127.     currentLoad = 1 - ((double)lowTicks)/maxIdle;
  2128.     }
  2129.  
  2130.     if (debug) {
  2131. #ifdef DEBUG
  2132.     Io_PrintStream(io_StdErr,
  2133.      "OldStatsPtr->lowTicks=%d, newStatsPtr->lowTicks=%d.\n",
  2134.                oldStatsPtr->lowTicks, newStatsPtr->lowTicks);
  2135. #endif
  2136.     Io_PrintStream(io_StdErr,
  2137.                "Idle ticks %d/%d => %6.2f%% Utilization, Queue length %d.\n",
  2138.                lowTicks,
  2139.                maxIdle,
  2140.                currentLoad * 100,
  2141.                newStatsPtr->queueLength);
  2142.     Io_Flush(io_StdErr);
  2143.     }
  2144.  
  2145.     if (!init) {
  2146.     init = TRUE;
  2147.     for (i = 0; i < LOAD_NUM_VALUES; i++) {
  2148.         loads[i].utilization = currentLoad;
  2149.         loads[i].queueLength = newStatsPtr->queueLength;
  2150.     }
  2151.     } else {
  2152.     for (i = 0; i < LOAD_NUM_VALUES; i++) {
  2153.         loads[i].utilization = weights[i] * loads[i].utilization +
  2154.             (1 - weights[i]) * currentLoad;
  2155.         loads[i].queueLength = weights[i] * loads[i].queueLength +
  2156.             (1 - weights[i]) * newStatsPtr->queueLength;
  2157.     }
  2158.     }
  2159. }
  2160.  
  2161.  
  2162. /*
  2163.  *----------------------------------------------------------------------
  2164.  *
  2165.  * GetStats --
  2166.  *
  2167.  *    Get the current number of idle ticks and the length of the
  2168.  *    ready queue.
  2169.  *
  2170.  * Results:
  2171.  *     The number of ticks and length of the ready queue are
  2172.  *    returned in *statsPtr.  The current time and time since last user
  2173.  *    input are also returned.
  2174.  *
  2175.  * Side effects:
  2176.  *    The global variable 'maxIdle' is initialized to
  2177.  *    idleTicksPerSecond * LOAD_INTERVAL.
  2178.  *
  2179.  *----------------------------------------------------------------------
  2180.  */
  2181.  
  2182. void
  2183. GetStats(statsPtr, timePtr, noInputPtr)
  2184.     Stats *statsPtr;
  2185.     Time *timePtr;
  2186.     int *noInputPtr;
  2187. {
  2188.     Sched_Instrument stats;
  2189.     static Boolean init = FALSE;
  2190.  
  2191.     Test_Stats(SCHED_STATS, 0, &stats);
  2192.     statsPtr->lowTicks = stats.idleTicksLow;
  2193.     statsPtr->highTicks = stats.idleTicksOverflow;
  2194.     statsPtr->queueLength = stats.numReadyProcesses;
  2195.     *noInputPtr = stats.noUserInput.seconds;
  2196.  
  2197.     if (timePtr != NULL) {
  2198.     Sys_GetTimeOfDay(timePtr, NULL, NULL);
  2199.     }
  2200.     if (!init) {
  2201.     maxIdle = stats.idleTicksPerSecond * LOAD_INTERVAL;
  2202.     init = TRUE;
  2203.     }
  2204.  
  2205. }
  2206.  
  2207.  
  2208. /*
  2209.  *----------------------------------------------------------------------
  2210.  *
  2211.  * OutputLoads --
  2212.  *
  2213.  *    Write the most recent utilization information to a file or to the
  2214.  *    standard output.  If writing to a file, reposition to write the
  2215.  *    data in the record corresponding to the ID of the current host.
  2216.  *
  2217.  * Results:
  2218.  *     None.
  2219.  *
  2220.  * Side effects:
  2221.  *    Data is output to a file (or to the standard output).
  2222.  *
  2223.  *----------------------------------------------------------------------
  2224.  */
  2225.  
  2226. void
  2227. OutputLoads(streamID, loads, time, noInput)
  2228.     int streamID;
  2229.     Load loads[];
  2230.     Time time;
  2231.     int noInput;
  2232. {
  2233.     static IOC_RepositionArgs args;
  2234.     static init = FALSE;
  2235.     int oldOffset;        /* ignored */
  2236.     static char utilRecord[UTIL_RECORD_SIZE];
  2237.     int bytesWritten;
  2238.     ReturnStatus status;
  2239.  
  2240.     if (!init) {
  2241.     init = TRUE;
  2242.     args.base = IOC_BASE_ZERO;
  2243.     args.offset = hostID * UTIL_RECORD_SIZE;
  2244.     Byte_Zero(UTIL_RECORD_SIZE, utilRecord);
  2245.     }
  2246. #ifdef notdef
  2247.     if (debug) {
  2248.     Io_PrintStream(io_StdErr, "OutputLoads: streamID = %d.\n", streamID);
  2249.     Io_Flush(io_StdErr);
  2250.     }
  2251. #endif
  2252.  
  2253.     Io_PrintString(utilRecord,
  2254.            "%2d %3d %10u %10u %3.0f %3.0f %3.0f %5.2f %5.2f %5.2f\n",
  2255.            LA_RPC_UPDATE, hostID, time.seconds, noInput,
  2256.            loads[0].utilization * 100, loads[1].utilization * 100,
  2257.            loads[2].utilization * 100,
  2258.            loads[0].queueLength, loads[1].queueLength,
  2259.            loads[2].queueLength);
  2260.  
  2261.     if (lockFile) {
  2262.     status = Fs_Lock(streamID, FS_LOCK_EXCLUSIVE);
  2263.     if (status != SUCCESS) {
  2264.         Stat_PrintMsg(status, "Error in Fs_Lock");
  2265.         Proc_Exit(status);
  2266.     }
  2267.     }
  2268.     if (useDataFile) {
  2269.     status = IOC_Reposition(streamID, &args, &oldOffset);
  2270.     if (status != SUCCESS) {
  2271.         Stat_PrintMsg(status, "Error in IOC_Reposition");
  2272.         Proc_Exit(status);
  2273.     }
  2274.     }
  2275.     status = Fs_Write(streamID, UTIL_RECORD_SIZE, utilRecord,
  2276.               &bytesWritten);
  2277.     if (status != SUCCESS) {
  2278.     Stat_PrintMsg(status, "Error in Fs_Read");
  2279.     Proc_Exit(status);
  2280.     }
  2281.     if (bytesWritten != UTIL_RECORD_SIZE) {
  2282.     Io_PrintStream(io_StdErr, "Only %d bytes written.\n", bytesWritten);
  2283.     Proc_Exit(FAILURE);
  2284.     }
  2285.     if (lockFile) {
  2286.     status = Fs_Lock(streamID, FS_LOCK_EXCLUSIVE | FS_UNLOCK);
  2287.     if (status != SUCCESS) {
  2288.         Stat_PrintMsg(status, "Error in Fs_Lock while unlocking file");
  2289.         Proc_Exit(status);
  2290.     }
  2291.     }
  2292. }
  2293.  
  2294.  
  2295.  
  2296. /*
  2297.  *----------------------------------------------------------------------
  2298.  *
  2299.  * RunServer --
  2300.  *
  2301.  *    (Optionally) fork a child to be the global server.  This daemon will
  2302.  *    receive load information from local daemons using named
  2303.  *    pipes and respond to requests for lighty-loaded machines.
  2304.  *
  2305.  * Results:
  2306.  *    None.
  2307.  *
  2308.  * Side effects:
  2309.  *    A second process may be created.
  2310.  *
  2311.  *----------------------------------------------------------------------
  2312.  */
  2313.  
  2314. void
  2315. RunServer()
  2316. {
  2317.     ReturnStatus status;
  2318.     NodeInfo nodeInfo[MAX_NUM_HOSTS];
  2319.     Proc_PID pid;
  2320.     int requestStreamID;
  2321.     int responseStreamID;
  2322.     char fileName[FS_MAX_PATH_NAME_LENGTH];
  2323.     int i;
  2324.     int bytesRead;
  2325.     char buffer[UTIL_RECORD_SIZE];
  2326.     char *bufPtr;
  2327.     int numScanned;
  2328.     int flags;
  2329.     int requestType;
  2330.  
  2331.  
  2332.     if (forkChild) {
  2333.     status = Proc_Fork(FALSE, &pid);
  2334.     } else {
  2335.     status = PROC_CHILD_PROC;
  2336.     }
  2337.     if (status == PROC_CHILD_PROC) {
  2338.     Io_PrintString(fileName, "%s/%s", pipeDir, requestFile);
  2339.     flags = FS_READ | FS_NAMED_PIPE_OPEN;
  2340.     if (debug) {
  2341.         Io_PrintStream(io_StdErr, "Opening file %s.\n", fileName);
  2342.         Io_Flush(io_StdErr);
  2343.     }
  2344.     status = Fs_Open(fileName, flags, 0, &requestStreamID);
  2345.     if (status != SUCCESS) {
  2346.         Stat_PrintMsg(status, "Error in Fs_Open");
  2347.         Proc_Exit(status);
  2348.     }
  2349.  
  2350.     Io_PrintString(fileName, "%s/%s", pipeDir, responseFile);
  2351.     flags = FS_WRITE | FS_CREATE | FS_NAMED_PIPE_OPEN;
  2352.     if (debug) {
  2353.         Io_PrintStream(io_StdErr, "Opening file %s.\n", fileName);
  2354.         Io_Flush(io_StdErr);
  2355.     }
  2356.     status = Fs_Open(fileName, flags, OPEN_MODE, &responseStreamID);
  2357.     if (status != SUCCESS) {
  2358.         Stat_PrintMsg(status, "Error in Fs_Open");
  2359.         Proc_Exit(status);
  2360.     }
  2361.  
  2362.     for (i = 0; i < MAX_NUM_HOSTS; i++) {
  2363.         nodeInfo[i].timestamp = NIL;
  2364.     }
  2365.  
  2366.     while(TRUE) {
  2367.         status = Fs_Read(requestStreamID, UTIL_RECORD_SIZE, buffer,
  2368.                  &bytesRead);
  2369.         if (status != SUCCESS) {
  2370.         Stat_PrintMsg(status, "Error in Fs_Read");
  2371.         Proc_Exit(status);
  2372.         }
  2373.         if (bytesRead != UTIL_RECORD_SIZE) {
  2374.         Io_PrintStream(io_StdErr, "Only %d bytes read.\n",
  2375.                    bytesRead);
  2376.         Proc_Exit(FAILURE);
  2377.         }
  2378.         bufPtr = buffer;
  2379.         numScanned = Io_ScanString(bufPtr, "%2d", &requestType);
  2380.         if (numScanned != 1) {
  2381.         Io_PrintStream(io_StdErr,
  2382.        "Error scanning request type from pipe.  Input string is '%s'.\n",
  2383.                    bufPtr);
  2384.         Proc_Exit(FAILURE);
  2385.         }
  2386.         bufPtr += 3;
  2387.         switch (requestType) {
  2388.         case LA_RPC_UPDATE: {
  2389.             UpdateData(bufPtr, nodeInfo);
  2390.             break;
  2391.         }
  2392.         case LA_RPC_IDLE: {
  2393. #ifdef notdone
  2394.             PrintIdleNode(nodeInfo);
  2395. #else
  2396.             PrintAllInfo(nodeInfo);
  2397. #endif
  2398.             break;
  2399.         }
  2400.         case LA_RPC_ALL_INFO: {
  2401.             PrintAllInfo(nodeInfo);
  2402.             break;
  2403.         }
  2404.         }
  2405.     }
  2406.     } else if (status != SUCCESS) {
  2407.     Stat_PrintMsg(status, "Error in Proc_Fork");
  2408.     Proc_Exit(status);
  2409.     }
  2410. }
  2411.  
  2412.  
  2413. /*
  2414.  *----------------------------------------------------------------------
  2415.  *
  2416.  * UpdateData --
  2417.  *
  2418.  *    Update the information for a node.
  2419.  *
  2420.  * Results:
  2421.  *    None.
  2422.  *
  2423.  * Side effects:
  2424.  *    'nodeInfo' is updated for the specified host.
  2425.  *
  2426.  *----------------------------------------------------------------------
  2427.  */
  2428.  
  2429. void
  2430. UpdateData(bufPtr, nodeInfo)
  2431.     char *bufPtr;        /* buffer containing data to be parsed */
  2432.     NodeInfo nodeInfo[];    /* pointer to array of per-node data */
  2433. {
  2434.     int numScanned;
  2435.     int hostID;
  2436.     NodeInfo info;
  2437.  
  2438.     numScanned = Io_ScanString(bufPtr,
  2439.                    "%d %d %d %d %d %d %lf %lf %lf",
  2440.                    &hostID,
  2441.                    &info.timestamp,
  2442.                    &info.noInput,
  2443.                    &info.utils[0],
  2444.                    &info.utils[1],
  2445.                    &info.utils[2],
  2446.                    &info.lengths[0],
  2447.                    &info.lengths[1],
  2448.                    &info.lengths[2]);
  2449.     if (numScanned != 9) {
  2450.     Io_PrintStream(io_StdErr,
  2451. "Error scanning information from request pipe.  Scanned %d items.\n",
  2452.                numScanned);
  2453.     Proc_Exit(FAILURE);
  2454.     }
  2455.     if (hostID <= 0 || hostID >= MAX_NUM_HOSTS) {
  2456.     Io_PrintStream(io_StdErr, "Invalid hostID: %d.\n", hostID);
  2457.     Proc_Exit(FAILURE);
  2458.     }
  2459.     if (debug) {
  2460.     Io_PrintStream(io_StdErr,
  2461.                "Received info from node %d.\n", hostID);
  2462.     Io_Flush(io_StdErr);
  2463.     }
  2464.     nodeInfo[hostID] = info;
  2465. }
  2466.  
  2467.  
  2468. /*
  2469.  *----------------------------------------------------------------------
  2470.  *
  2471.  * PrintAllInfo --
  2472.  *
  2473.  *    Print statistics for all nodes.
  2474.  *
  2475.  * Results:
  2476.  *    None.
  2477.  *
  2478.  * Side effects:
  2479.  *    Data is written to io_StdOut.
  2480.  *
  2481.  *----------------------------------------------------------------------
  2482.  */
  2483.  
  2484. void
  2485. PrintAllInfo(nodeInfo)
  2486.     NodeInfo nodeInfo[];    /* array of per-node data */
  2487. {
  2488.     int hostID;
  2489.  
  2490.     if (debug) {
  2491.     Io_PrintStream(io_StdErr,
  2492.                "Received request for idle node.\n");
  2493.     }
  2494.     for (hostID = 0; hostID < MAX_NUM_HOSTS; hostID++) {
  2495.     if (nodeInfo[hostID].timestamp != NIL) {
  2496.         Io_PrintStream(io_StdErr,
  2497.                "%3d %10u %10u %3d %3d %3d %5.2lf %5.2lf %5.2lf\n",
  2498.                hostID,
  2499.                nodeInfo[hostID].timestamp,
  2500.                nodeInfo[hostID].noInput,
  2501.                nodeInfo[hostID].utils[0],
  2502.                nodeInfo[hostID].utils[1],
  2503.                nodeInfo[hostID].utils[2],
  2504.                nodeInfo[hostID].lengths[0],
  2505.                nodeInfo[hostID].lengths[1],
  2506.                nodeInfo[hostID].lengths[2]);
  2507.     }
  2508.     }
  2509.     Io_Flush(io_StdErr);
  2510. }
  2511.  
  2512.  
  2513. /*
  2514.  *----------------------------------------------------------------------
  2515.  *
  2516. d194 1
  2517. a194 6
  2518. /*
  2519.  * Arbitrary value larger than the load average on any node
  2520.  */
  2521. #define MAX_LOAD 1000.0
  2522.  
  2523. void
  2524. a351 2
  2525.     
  2526.       
  2527. @
  2528.  
  2529.  
  2530. 1.7
  2531. log
  2532. @successfully prints out list of load averages for shared file case.
  2533. @
  2534. text
  2535. @d13 1
  2536. a13 1
  2537. static char rcsid[] = "$Header: loadAvg.c,v 1.6 87/03/03 14:57:39 douglis Exp $ SPRITE (Berkeley)";
  2538. a57 1
  2539. #define OPEN_WRITE_FLAGS (FS_WRITE | FS_CREATE)
  2540. d62 2
  2541. a63 2
  2542.  * A record contains "%2d %3d %10d %3.0f %3.0f %3.0f %5.2f %5.2f %5.2f\n",
  2543.  * plus a null byte.  (This amounts to 43 bytes.)  Make it the next
  2544. d148 4
  2545. a151 3
  2546.     int        utils[LOAD_NUM_VALUES];
  2547.     double    lengths[LOAD_NUM_VALUES];
  2548.     int        timestamp;
  2549. a155 2
  2550. void  RunDaemon(), RunServer(), GetStats(), PrintAllInfo(),
  2551.     OutputLoads(), CalculateLoads(), GetIdleNode(), UpdateData();
  2552. d157 10
  2553. d301 1
  2554. a301 1
  2555.     int flags = OPEN_WRITE_FLAGS;
  2556. d307 1
  2557. d331 1
  2558. a331 1
  2559.         status = Fs_Open(fileName, flags, mode, &streamID);
  2560. d344 1
  2561. a344 1
  2562.     GetStats(&stats[0], (Time *) NULL);
  2563. d354 1
  2564. a354 1
  2565.         GetStats(&stats[nextStat], &time);
  2566. d424 1
  2567. a424 1
  2568.     Io_PrintStream(io_StdErr, "Lowticks=%u.\n", lowTicks);
  2569. d441 1
  2570. a441 1
  2571.          "OldStatsPtr->lowTicks=%u, newStatsPtr->lowTicks=%u.\n",
  2572. d445 1
  2573. a445 1
  2574.                "Idle ticks %d/%u => %6.2f%% Utilization, Queue length %d.\n",
  2575. d480 2
  2576. a481 1
  2577.  *    returned in *statsPtr.
  2578. d491 1
  2579. a491 1
  2580. GetStats(statsPtr, timePtr)
  2581. d494 1
  2582. d503 1
  2583. d535 1
  2584. a535 1
  2585. OutputLoads(streamID, loads, time)
  2586. d539 1
  2587. d562 2
  2588. a563 2
  2589.            "%2d %3d %10d %3.0f %3.0f %3.0f %5.2f %5.2f %5.2f\n",
  2590.            LA_RPC_UPDATE, hostID, time.seconds,
  2591. d747 1
  2592. a747 1
  2593.                    "%3d %10d %d %d %d %lf %lf %lf",
  2594. d750 1
  2595. d757 1
  2596. a757 1
  2597.     if (numScanned != 8) {
  2598. d797 1
  2599. a797 1
  2600.     
  2601. d805 1
  2602. a805 1
  2603.                "%3d %10d %3d %3d %3d %5.2lf %5.2lf %5.2lf\n",
  2604. d808 1
  2605. d871 1
  2606. a871 1
  2607.     status = Fs_Open(fileName, (OPEN_WRITE_FLAGS | FS_NAMED_PIPE_OPEN),
  2608. d925 1
  2609. a925 1
  2610.              i++, utilPtr += UTIL_RECORD_SIZE) {
  2611. d928 1
  2612. a928 1
  2613.                "%*d %d %d %d %d %d %lf %lf %lf",
  2614. d931 1
  2615. d938 1
  2616. a938 1
  2617.         if (numScanned != 8) {
  2618. d940 1
  2619. a940 1
  2620.             "Error scanning data for node %d.  Scanned only %d items.\n",
  2621. d948 1
  2622. a948 1
  2623.             "Mismatch between counter (%d) and value in data file (%d).\n",
  2624. d952 2
  2625. a953 2
  2626.         Io_Print("Node %d\tload average %5.2lf.\n", hostID,
  2627.              nodeInfo.lengths[2]);
  2628. d963 39
  2629. @
  2630.  
  2631.  
  2632. 1.6
  2633. log
  2634. @Changed weights to be exact values for 1, 5, and 15 minute averages. 
  2635. Maintain avg. ready-queue lengths.  Wrote initial code for server
  2636. process (using named pipes).
  2637. @
  2638. text
  2639. @d1 1
  2640. a1 1
  2641. /* 
  2642. d13 1
  2643. a13 1
  2644. static char rcsid[] = "$Header: loadAvg.c,v 1.5 87/02/23 20:13:41 douglis Exp $ SPRITE (Berkeley)";
  2645. d28 1
  2646. d31 12
  2647. d46 1
  2648. a46 1
  2649. #define LOAD_INTERVAL 5    
  2650. d48 2
  2651. a49 2
  2652. #define WEIGHT1 (double) 0.9200444146293232     /* exp(-1/12) */ 
  2653. #define WEIGHT2 (double) 0.9834714538216174     /* exp(-1/60) */ 
  2654. d51 3
  2655. a53 3
  2656. #define LOAD_NUM_VALUES 3                       
  2657.                                                            
  2658. /* 
  2659. d58 1
  2660. a58 1
  2661. #define OPEN_FLAGS (FS_WRITE | FS_CREATE)
  2662. d63 2
  2663. a64 2
  2664.  * A record contains "%3d %10d %3.0f %3.0f %3.0f %5.2f %5.2f %5.2f\n",
  2665.  * plus a null byte.  (This amounts to 40 bytes.)  Make it the next
  2666. d70 2
  2667. a71 2
  2668. Boolean daemon = FALSE;
  2669. Boolean server = FALSE;
  2670. d75 2
  2671. a76 2
  2672. Boolean writeToDataFile = FALSE;
  2673. Boolean writeToPipe = FALSE;
  2674. d78 1
  2675. a80 1
  2676. Boolean ioTest = FALSE;
  2677. d89 6
  2678. a94 2
  2679.     {OPT_TRUE, 'd', (Address)&daemon, 
  2680.     "Run as a daemon and report load information to the global server."},
  2681. d97 1
  2682. a97 1
  2683.     "Interval between iterations for getting load info (default 1 second)"},
  2684. d100 8
  2685. a107 8
  2686.     {OPT_TRUE, 'F', (Address)&forkChild, "Fork off the daemon."},
  2687.     {OPT_TRUE, 'f', (Address)&writeToDataFile,
  2688.             "Output options:\n\tOutput daemon's info to data file (DEFAULT)."},
  2689.     {OPT_TRUE, 'p', (Address)&writeToPipe,
  2690.          "\tOutput daemon's info to named pipe."},
  2691.     {OPT_TRUE, 's', (Address)&writeToStdOut,
  2692.          "\tOutput daemon's info to standard output."},
  2693.     {OPT_TRUE, 'l', (Address)&lockFile,
  2694. d111 2
  2695. d117 1
  2696. a117 5
  2697.     {OPT_TRUE, 'S', (Address)&server, 
  2698.          "Run as a daemon maintaining the global state."},
  2699.     {OPT_STRING, 'P', (Address)&pipeDir,
  2700.          "Directory containing named pipes (default \"/etc/daemons\")."},
  2701.     {OPT_STRING, 'w', (Address)&weightString,
  2702. d124 1
  2703. a124 1
  2704.  * at some instant in time. 
  2705. d143 1
  2706. a143 1
  2707. /* 
  2708. d149 2
  2709. a150 1
  2710.     Load    loads[LOAD_NUM_VALUES];
  2711. d156 2
  2712. a157 1
  2713. void  RunDaemon(), RunServer(), GetStats(), OutputLoads(), CalculateLoads();
  2714. d199 3
  2715. a201 14
  2716.     if (ioTest) {
  2717.     Io_Print("Testing: %3.0f %3.0f %3.0f %3.0f %3.0f ...\n",
  2718.          0.0, 0.01, 0.001, 0.0001, 0.00001);
  2719.     status = Io_Error(io_StdOut);
  2720.     if (status != SUCCESS) {
  2721.         Stat_PrintMsg(status, "Error in Io_Print");
  2722.         Proc_Exit(status);
  2723.     }
  2724.     Io_Flush(io_StdOut);
  2725.     }
  2726.     
  2727.     if (! (writeToDataFile || writeToPipe || writeToStdOut)) {
  2728.     writeToDataFile = TRUE;
  2729.     } else if (AND3(writeToDataFile, writeToPipe, writeToStdOut)) {
  2730. d203 1
  2731. a203 1
  2732.                "%s: may only write to one of data-file/pipe/console.\n",
  2733. d207 12
  2734. a218 1
  2735.     if (lockFile && !writeToDataFile) {
  2736. d235 5
  2737. a239 1
  2738.     if (debug) {
  2739. d249 2
  2740. a250 2
  2741.     
  2742.     if (daemon) {
  2743. d253 7
  2744. d271 1
  2745. a271 1
  2746.  *    pipes. 
  2747. d293 1
  2748. a293 1
  2749.     int flags = OPEN_FLAGS;
  2750. d310 2
  2751. a311 2
  2752.     if (writeToDataFile || writeToPipe) {
  2753.         if (writeToDataFile) {
  2754. d334 1
  2755. a334 1
  2756.     
  2757. d455 1
  2758. a455 1
  2759.             (1 - weights[i]) * newStatsPtr->queueLength; 
  2760. d500 1
  2761. a500 1
  2762.     
  2763. d541 1
  2764. d546 2
  2765. a547 1
  2766.     
  2767. d549 4
  2768. a552 3
  2769.            "%3d %10d %3.0f %3.0f %3.0f %5.2f %5.2f %5.2f\n",
  2770.            hostID, time.seconds, loads[0].utilization * 100,
  2771.            loads[1].utilization * 100, loads[2].utilization * 100,
  2772. d554 2
  2773. a555 2
  2774.            loads[2].queueLength); 
  2775.     
  2776. d563 1
  2777. a563 1
  2778.     if (writeToDataFile) {
  2779. a613 1
  2780.     NodeInfo info;
  2781. d621 1
  2782. d624 1
  2783. a624 1
  2784.     int timestamp;
  2785. d673 2
  2786. a674 1
  2787.         numScanned = Io_ScanString(buffer, "%3d", &hostID);
  2788. d677 2
  2789. a678 1
  2790.                "Error scanning hostID from request pipe.\n");
  2791. d681 5
  2792. a685 4
  2793.         if (hostID > 0) {
  2794.         if (hostID >= MAX_NUM_HOSTS) {
  2795.             Io_PrintStream(io_StdErr, "Invalid hostID: %d.\n", hostID);
  2796.             Proc_Exit(FAILURE);
  2797. d687 7
  2798. a693 13
  2799.         numScanned = Io_ScanString(&buffer[4],
  2800.                 "%10d %3.0f %3.0f %3.0f %5.2f %5.2f %5.2f",
  2801.             &info.timestamp,
  2802.             &info.loads[0].utilization,
  2803.             &info.loads[1].utilization,
  2804.             &info.loads[2].utilization,
  2805.             &info.loads[0].queueLength,
  2806.             &info.loads[1].queueLength,
  2807.             &info.loads[2].queueLength);
  2808.         if (numScanned != 7) {
  2809.             Io_PrintStream(io_StdErr,
  2810.                    "Error scanning information from request pipe.\n");
  2811.             Proc_Exit(FAILURE);
  2812. d695 3
  2813. a697 5
  2814.         nodeInfo[hostID] = info;
  2815.         } else {
  2816.         if (debug) {
  2817.             Io_PrintStream(io_StdErr,
  2818.                    "Received request for idle node.\n");
  2819. a698 14
  2820.         for (i = 0; i < MAX_NUM_HOSTS; i++) {
  2821.             if (nodeInfo[i].timestamp != NIL) {
  2822.             Io_PrintStream(io_StdErr,
  2823.                     "3d %10d %3.0f %3.0f %3.0f %5.2f %5.2f %5.2f\n",
  2824.                 i,
  2825.                 nodeInfo[i].timestamp,
  2826.                 nodeInfo[i].loads[0].utilization,
  2827.                 nodeInfo[i].loads[1].utilization,
  2828.                 nodeInfo[i].loads[2].utilization,
  2829.                 nodeInfo[i].loads[0].queueLength,
  2830.                 nodeInfo[i].loads[1].queueLength,
  2831.                 nodeInfo[i].loads[2].queueLength);
  2832.             }
  2833.         }
  2834. d706 241
  2835. @
  2836.  
  2837.  
  2838. 1.5
  2839. log
  2840. @use exponential decay w/ period of 1 second.
  2841. @
  2842. text
  2843. @d13 1
  2844. a13 1
  2845. static char rcsid[] = "$Header: loadAvg.c,v 1.4 87/02/19 15:47:20 douglis Exp $ SPRITE (Berkeley)";
  2846. d27 1
  2847. d29 3
  2848. a31 5
  2849. #define LOAD_INTERVAL 1
  2850. #define WEIGHT1 (double) .2
  2851. #define WEIGHT2 (double) .9
  2852. #define WEIGHT3 (double) .99
  2853. #define LOAD_NUM_VALUES 3
  2854. d33 11
  2855. d47 1
  2856. d50 3
  2857. a52 1
  2858.  * A record contains "%3d %10d %3.0f %3.0f %3.0f\n", plus a null byte.
  2859. d55 1
  2860. a55 1
  2861. #define UTIL_RECORD_SIZE (4 + 11 + (LOAD_NUM_VALUES * 4) + 1)
  2862. d58 1
  2863. d60 2
  2864. d76 2
  2865. a77 1
  2866.     {OPT_TRUE, 'd', (Address)&daemon, "Run as a daemon and report load information to the global server."},
  2867. d79 4
  2868. a91 2
  2869.     {OPT_TRUE, 'I', (Address)&ioTest,
  2870.          "Do a silly test of Io_Print."},
  2871. d98 2
  2872. d107 5
  2873. d118 20
  2874. d140 1
  2875. a140 1
  2876. void RunDaemon(), GetStats(), OutputLoads(), CalculateLoads();
  2877. d260 1
  2878. a260 1
  2879.     double loads[LOAD_NUM_VALUES];
  2880. d269 2
  2881. d279 1
  2882. a279 1
  2883.     sleepTime.seconds = LOAD_INTERVAL;
  2884. d313 2
  2885. d320 4
  2886. a323 1
  2887.         OutputLoads(streamID, loads, time);
  2888. d342 2
  2889. a343 1
  2890.  *    the utilization of the computer during that period of time.
  2891. d345 2
  2892. d348 2
  2893. a349 2
  2894.  *    The calculated utilization is returned in
  2895.  *    loadsPtr[0..LOAD_NUM_VALUES].
  2896. d361 1
  2897. a361 1
  2898.     double loads[];
  2899. d408 1
  2900. a408 1
  2901.                "Idle ticks %d/%u => %6.2f%% Utilization.\n",
  2902. d411 2
  2903. a412 1
  2904.                currentLoad * 100);
  2905. d419 2
  2906. a420 1
  2907.         loads[i] = currentLoad;
  2908. d424 1
  2909. a424 1
  2910.         loads[i] = weights[i] * loads[i] +
  2911. d426 2
  2912. d463 1
  2913. a463 3
  2914. #ifdef READY_QUEUE    
  2915.     statsPtr->queueLength = stats.queueLength;
  2916. #endif READY_QUEUE    
  2917. d497 1
  2918. a497 1
  2919.     double loads[];
  2920. d503 1
  2921. a503 1
  2922.     char utilRecord[UTIL_RECORD_SIZE];
  2923. d507 6
  2924. d518 6
  2925. a523 3
  2926.     Io_PrintString(utilRecord, "%3d %10d %3d %3d %3d\n",
  2927.            hostID, time.seconds, (int) (loads[0] * 100),
  2928.            (int) (loads[1] * 100), (int) (loads[2] * 100)); 
  2929. a532 5
  2930.     if (!init) {
  2931.         init = TRUE;
  2932.         args.base = IOC_BASE_ZERO;
  2933.         args.offset = hostID * UTIL_RECORD_SIZE;
  2934.     }
  2935. d558 136
  2936. @
  2937.  
  2938.  
  2939. 1.4
  2940. log
  2941. @fixed problem w/ filename for named pipe.
  2942. @
  2943. text
  2944. @d13 1
  2945. a13 1
  2946. static char rcsid[] = "$Header: loadAvg.c,v 1.2 87/02/15 22:31:46 douglis Exp $ SPRITE (Berkeley)";
  2947. d28 5
  2948. a32 7
  2949. #define LOAD_INTERVAL 5
  2950. #define LOAD_NUM_INTS_1 1
  2951. #define LOAD_NUM_INTS_2 2
  2952. #define LOAD_NUM_INTS_3 10
  2953. #define LOAD_NUM_INTERVALS LOAD_NUM_INTS_3
  2954. static int loadIntervals[] = {1, 2, LOAD_NUM_INTERVALS};
  2955. #define LOAD_NUM_VALUES (sizeof(loadIntervals) / sizeof(int))
  2956. d51 1
  2957. d56 2
  2958. d71 2
  2959. d81 2
  2960. d89 2
  2961. a90 2
  2962.     Time    time;
  2963. } UtilInfo;
  2964. d94 1
  2965. a94 1
  2966. void RunDaemon(), GetIdleTicks(), OutputUtil();
  2967. d96 1
  2968. a96 2
  2969. static unsigned int idleTicksPerSecond;
  2970. double CalculateUtil();
  2971. d112 1
  2972. a112 1
  2973.  *    Variable.
  2974. d123 1
  2975. d136 10
  2976. d157 1
  2977. a157 1
  2978.         "%s: may only specify lock (-l) option if writing to a data file.",
  2979. d161 16
  2980. a176 1
  2981.         
  2982. d195 1
  2983. a195 1
  2984.  *    Fork off a child to be the local daemon.  This daemon will
  2985. d203 1
  2986. a203 1
  2987.  *    A second process is created.
  2988. a211 2
  2989.     UtilInfo utilArray[LOAD_NUM_INTERVALS];
  2990.     UtilInfo latestInfo;
  2991. d213 2
  2992. a214 4
  2993.     int i;
  2994.     int matchingInterval;
  2995.     double utils[LOAD_NUM_VALUES];
  2996.     int currentInterval;
  2997. d221 2
  2998. a230 7
  2999.     for (i = 0; i < LOAD_NUM_INTERVALS; i++) {
  3000.         utilArray[i].lowTicks = 0;
  3001.         utilArray[i].highTicks = NIL;
  3002.         utilArray[i].time = time_ZeroSeconds;
  3003.     }
  3004.     GetIdleTicks(&utilArray[0]);
  3005.     currentInterval = 1;
  3006. d254 12
  3007. d267 4
  3008. a274 21
  3009.         GetIdleTicks(&latestInfo);
  3010.         for (i = 0; i < LOAD_NUM_VALUES; i++) {
  3011.         matchingInterval = (currentInterval - loadIntervals[i] +
  3012.                     LOAD_NUM_INTERVALS) % LOAD_NUM_INTERVALS;
  3013.         if (utilArray[matchingInterval].highTicks != NIL) {
  3014.             if (debug) {
  3015.             Io_PrintStream(io_StdErr,
  3016.                        "%d-second average utilization:",
  3017.                        loadIntervals[i] * LOAD_INTERVAL);
  3018.             Io_Flush(io_StdErr);
  3019.             }
  3020.  
  3021.             utils[i] = CalculateUtil(&utilArray[matchingInterval],
  3022.                          &latestInfo);
  3023.         } else {
  3024.             utils[i] = utils[i-1];
  3025.         }
  3026.         }
  3027.         OutputUtil(streamID, utils, latestInfo.time);
  3028.         utilArray[currentInterval] = latestInfo;
  3029.         currentInterval = (currentInterval + 1) % LOAD_NUM_INTERVALS;
  3030. d286 1
  3031. a286 1
  3032.  * CalculateUtil --
  3033. d292 2
  3034. a293 1
  3035.  *    The calculated utilization is returned.
  3036. d301 5
  3037. a305 4
  3038. double
  3039. CalculateUtil(oldInfoPtr, newInfoPtr)
  3040.     UtilInfo *oldInfoPtr;
  3041.     UtilInfo *newInfoPtr;
  3042. d307 6
  3043. a312 4
  3044.     Time timeDiff;
  3045.     double util;
  3046.     double maxIdle;
  3047.     register unsigned highTicks, lowTicks;
  3048. d314 6
  3049. a319 4
  3050.     highTicks = newInfoPtr->highTicks - oldInfoPtr->highTicks;
  3051.     lowTicks = newInfoPtr->lowTicks - oldInfoPtr->lowTicks;
  3052.     if (highTicks != 0) {
  3053.     lowTicks =  ((int) lowTicks) + HIGH_TO_LOW_TICKS;
  3054. d321 6
  3055. d328 1
  3056. d331 1
  3057. a331 1
  3058.     Io_PrintStream(io_StdErr, "Lowticks=%d.\n", lowTicks);
  3059. d334 11
  3060. a344 5
  3061.     Time_Subtract(newInfoPtr->time, oldInfoPtr->time, &timeDiff);
  3062.     maxIdle = idleTicksPerSecond * ((double) timeDiff.seconds +
  3063.          ((double) timeDiff.microseconds) / 1000000.);
  3064.     
  3065.     util = ((double)lowTicks)/maxIdle;
  3066. d348 2
  3067. a349 3
  3068.          "OldInfoPtr->lowTicks=%d, newInfoPtr->lowTicks=%d, time = (%d,%d).\n",
  3069.                oldInfoPtr->lowTicks, newInfoPtr->lowTicks,
  3070.                timeDiff.seconds, timeDiff.microseconds);
  3071. d352 1
  3072. a352 1
  3073.                "Idle ticks %d/%5.0f = %6.2f%% Idle.\n",
  3074. d355 2
  3075. a356 1
  3076.                util * 100);
  3077. d358 12
  3078. a369 2
  3079.     Io_Flush(io_StdErr);
  3080.     return(util);
  3081. d376 1
  3082. a376 1
  3083.  * GetIdleTicks --
  3084. d378 2
  3085. a379 1
  3086.  *    Get the current number of idle ticks and the time.
  3087. d382 2
  3088. a383 1
  3089.  *     The number of ticks and time are returned in *utilPtr.
  3090. d386 2
  3091. a387 1
  3092.  *    None.
  3093. d393 3
  3094. a395 2
  3095. GetIdleTicks(utilPtr)
  3096.     UtilInfo *utilPtr;
  3097. d398 1
  3098. d401 5
  3099. a405 3
  3100.     utilPtr->lowTicks = stats.idleTicksLow;
  3101.     utilPtr->highTicks = stats.idleTicksOverflow;
  3102.     Sys_GetTimeOfDay(&(utilPtr->time), NULL, NULL);
  3103. d407 8
  3104. a414 1
  3105.     idleTicksPerSecond = stats.idleTicksPerSecond;
  3106. d421 1
  3107. a421 1
  3108.  * OutputUtil --
  3109. d437 1
  3110. a437 1
  3111. OutputUtil(streamID, utils, time)
  3112. d439 1
  3113. a439 1
  3114.     double utils[];
  3115. d450 1
  3116. a450 1
  3117.     Io_PrintStream(io_StdErr, "OutputUtil: streamID = %d.\n", streamID);
  3118. d454 3
  3119. a456 3
  3120.     Io_PrintString(utilRecord, "%3d %10d %3.0f %3.0f %3.0f\n",
  3121.            hostID, time.seconds,
  3122.            utils[0] * 100, utils[1] * 100, utils[2] * 100); 
  3123. d495 1
  3124. @
  3125.  
  3126.  
  3127. 1.3
  3128. log
  3129. @Allow writing data to single data file, named pipe, or stdout.  
  3130. @
  3131. text
  3132. @d192 1
  3133. d217 2
  3134. a218 1
  3135.         fileName = requestFile;
  3136. @
  3137.  
  3138.  
  3139. 1.2
  3140. log
  3141. @Currently works to the extent of printing out idle times on the
  3142. console.  Fs_Lock call bombs, so can't use a file yet.
  3143. @
  3144. text
  3145. @d13 1
  3146. a13 1
  3147. static char rcsid[] = "$Header: loadAvg.c,v 1.1 87/02/15 20:53:15 douglis Exp $ SPRITE (Berkeley)";
  3148. d37 2
  3149. a38 2
  3150. #define REQUEST_FLAGS (FS_WRITE | FS_CREATE)
  3151. #define REQUEST_MODE 0664
  3152. d41 1
  3153. a41 2
  3154.  * A record contains "%3d " for each value (i.e., 4 characters), plus "%10d"
  3155.  * for the time, plus a null byte.
  3156. d44 1
  3157. a44 1
  3158. #define UTIL_RECORD_SIZE ((LOAD_NUM_VALUES * 4) + 11)
  3159. d48 3
  3160. a50 1
  3161. Boolean writeToFile = TRUE;
  3162. d52 1
  3163. d56 1
  3164. d61 17
  3165. a77 5
  3166.     {OPT_TRUE, 'f', (Address)&forkChild, "Fork off the daemon."},
  3167.     {OPT_FALSE, 'F', (Address)&writeToFile,
  3168.          "Do not output daemon's info to file."},
  3169.     {OPT_STRING, 'r', (Address)&requestFile, "Request file name\n"},
  3170.     {OPT_STRING, 'R', (Address)&responseFile, "Response file name\n"},
  3171. d88 1
  3172. d126 21
  3173. d190 4
  3174. a193 1
  3175.     int requestID;
  3176. d195 1
  3177. d212 7
  3178. a218 1
  3179.     if (writeToFile) {
  3180. d220 1
  3181. a220 1
  3182.         Io_PrintStream(io_StdErr, "Opening file %s.\n", requestFile);
  3183. d223 1
  3184. a223 2
  3185.         status = Fs_Open(requestFile, REQUEST_FLAGS, REQUEST_MODE,
  3186.                  &requestID);
  3187. d229 1
  3188. a229 1
  3189.         requestID = STANDARD_OUTPUT;
  3190. d254 1
  3191. a254 1
  3192.         OutputUtil(requestID, utils, latestInfo.time);
  3193. d383 1
  3194. a383 1
  3195.     int oldOffset;                /* ignored */
  3196. a384 1
  3197.     int i;
  3198. d393 2
  3199. a394 1
  3200.     Io_PrintString(utilRecord, "%10d %3.0f %3.0f %3.0f", time.seconds,
  3201. d397 1
  3202. a397 1
  3203.     if (streamID != STANDARD_OUTPUT) {
  3204. d403 2
  3205. d415 13
  3206. a427 2
  3207.     status = Fs_Write(streamID, UTIL_RECORD_SIZE, utilRecord,
  3208.               &bytesWritten);
  3209. a428 9
  3210.         Stat_PrintMsg(status, "Error in Fs_Read");
  3211.         Proc_Exit(status);
  3212.     }
  3213.     if (bytesWritten != UTIL_RECORD_SIZE) {
  3214.         Io_PrintStream(io_StdErr, "Only %d bytes written.\n", bytesWritten);
  3215.         Proc_Exit(FAILURE);
  3216.     }
  3217.     status = Fs_Lock(streamID, FS_UNLOCK);
  3218.     if (status != SUCCESS) {
  3219. a429 8
  3220.         Proc_Exit(status);
  3221.     }
  3222.     } else {
  3223.     Io_Print("%s\n", utilRecord);
  3224.     Io_Flush(io_StdOut);
  3225.     status = Io_Error(io_StdOut);
  3226.     if (status != SUCCESS) {
  3227.         Stat_PrintMsg(status, "Error in Io_Print");
  3228. @
  3229.  
  3230.  
  3231. 1.1
  3232. log
  3233. @Initial revision
  3234. @
  3235. text
  3236. @d13 1
  3237. a13 1
  3238. static char rcsid[] = "$Header: proto.c,v 1.7 87/01/04 17:28:48 andrew Exp $ SPRITE (Berkeley)";
  3239. d37 2
  3240. d40 7
  3241. d50 1
  3242. d58 1
  3243. d73 1
  3244. a73 1
  3245. void RunDaemon(), GetIdleTicks();
  3246. d153 1
  3247. d155 1
  3248. a155 1
  3249.     if (!debug) {
  3250. d172 4
  3251. d183 3
  3252. a185 3
  3253.         streamID = STANDARD_OUTPUT;
  3254.  
  3255.         while(TRUE) {
  3256. a206 1
  3257.         OutputUtil(requestID, utils, latestInfo.time);
  3258. d208 1
  3259. d335 56
  3260. @
  3261.